  #include "mbn_evo.h"
	#ifdef win32   
	   #include "mylib.h"
  #else
     #include "../mylib.h"
  #endif 
  #include <vector>
  #include <algorithm>


  /******************************************************************
          Dichiarazione delle variabili esterne al file.
  ******************************************************************/

  int n_run=0;// numero_run

  extern Experiment experiment;
  /* E' l'oggetto della classe Experiment che memorizza tutti i dati dell'
     esperimento. */

  extern char *par_string;
  /** Questa stringa serve per associare un chiave di ricerca ai nodi padre
      (file node.cpp).  */

  graph *dag;
  query_database *db, *db2;
  ClassBN *bn;
  bool serialize = true;


 List<class Main_node>::iterator find_value
                         (List<class Main_node>::iterator start_iter,
		          List<class Main_node>::iterator end_iter,
                         int value);
 /* E' la procedura utilizzata dall'operatore di crossover.
 */

  query_database * _dummy_query = 0;
  query_database *init(const char * t_file = "", int test_num = 0, query_database* &dp = _dummy_query);
  /* Inizializza le funzioni per il calcolo dello score.
  */
  bool test_data;

 List<class Main_node> null_list;
 List<class Main_node>::iterator null_node = null_list.end();

 List<class Link> null_link_list;
 List<class Link>::iterator null_link = null_link_list.end();


  matrx<float> SeconOrderStatistic( query_database & db );
  matrx<float> SeconOrderStatistic2( query_database & db );
  matrx<float> SeconOrderStatistic3( query_database & db );
  /* Calcola lo score degli archi da usare x la knowledge guided mutation.
  */
  min_score *min_scores;


  matrx<float> G_statistics(query_database &db);
  /* Calcola la statistica G  per le variabili.
  */
  matrx<float>* buildMmatr(query_database &db);
   
  bool **buildSkeleton(float p_val, matrx<float> *m);
  /* E' la funzione che costruisce la matrice in cui sono memorizzate
     gli archi da considerare in base alla mutua informazione.
   */

  float Mutual(int x, int y, query_database &db);
  float G_test(int x, int y, query_database &db);

  vectr<float> FirstOrderStatistic( query_database & db );
  /* Calcola lo scored dei nodi singoli.
  */

  void swap_nodes(List<class Main_node> &multi, int node1, int node2);
  /* Efettua lo swap tra due elementi della multilista, lasciando inalterate
     le loro connessioni.
  */
  bool check_node(List<class Main_node> multi,
		 List<class Main_node>::iterator first_iter,
                 List<class Main_node>::iterator &second_iter, bool first);

  bool shift_node(List<class Main_node> &multi,
		 List<class Main_node>::iterator first_iter,
                 List<class Main_node>::iterator &second_iter, bool first);
  bool shift_node(List<class Main_node> &multi,
		 List<class Main_node>::iterator first_iter,
                 List<class Main_node>::iterator &second_iter, vectr<int>pars);

  void ini_min_scores(int n);
  float give_min_score(int node);
  bool is_father(int node, int f);

  vectr<int> build_DT_ord(graph *g, matrx<float> *m);

  void comp_mutual_values (mutual_values m, int N_nodes);
  /* Calcola tutti i valori  relativi alla mutua informazione: avg, std, max, min
  */ 

    bool sh[1000];

  /*************************************************************************
          Definizione delle procedure della classe MULTI_EVOLUTION
   ************************************************************************/


  /*
  ----------------- Procedura Multi_evolution ------------------------------
  *** Scritta il: 24/07/03
  E' la procedura che legge i vari file necessari all'evoluzione e genera
  la popolazione iniziale.

  *** Ultima modifica:
  */
  void Multi_evolution::start(int argc, char *argv[])
  {

    ofstream res_stream;

     ofstream graph_out;
     char aiseefile[30] = "target_graph.gdl";
     char serialfile[100] = "BNserialize.dat";


    /** Si settano i parametri per il calcolo della fitness.
        ATTENZIONE!: questi parametri devono andare sempre
        PRIMA della funzione get_params!*/
    cpx         = false;
    mdl         = false;
    k_cross     = false;
    micro_mut   = false;
    mutual_info = false;
    perm_mut    = false;
    /** Valori di default per i vincoli sul numero massimo di nodi
        anche questi vanno PRIMA di get_params!!!
    */
    max_pars = max_pars_label = 4;
    max_bads = 0;


    //  ******** Si legge il file dei parametri evolutivi. **********
    get_params(argc, argv);

    /** *************** SETTING AUTOMATICO della densità ************** 
     ** inserisce in media un numero di archi pari alla metà del numero
     ** di nodi.
     **/
    density = 1.0 / N_nodes;

    /** *************** SETTING della probabilita di micro-mutazione *********
     ** la probabilita di micro-mutazione è espressa in termini di Narchi.
     **/    
    if (micro_mut)
      mut_prob /= (N_nodes * (N_nodes - 1)) / 2;
   	       
     // ******** Si generano gli oggetti delle classi degli operatori. *****
     crossover = new Multi_crossover(this);
     mutation = new Multi_mutation(this);


     // Si genera il grafo da usare per la valutazione della fitness.
     dag = new graph(N_nodes);
     bn  = new ClassBN(N_nodes);
     
     char test_name[100], test_str[30];
     int  test_num; 
     
     if (read_param(argc, argv, (char *) "-t", test_name)) {
       if (read_param(argc, argv, (char *) "-ts", test_str)) { 
         test_num = atoi(test_str);
         db  = init(test_name, test_num, db2); 
         test_data = true;  
       }
       else abort_message((char *) "ERRORE: il numero di sample di test mancante!"); 
     } else {
         db = init();
         test_data = false;
       }

     /* Si alloca memoria per la stringa da utilizzare per la
        generazione della chiave. */
     par_string = new char[N_nodes];

     // Si inizializza il vettore che memorizza il minimo degli scores.
     ini_min_scores(db->getN());

    //  ******** Costruzione della matrice di mutua informazione. **********

     // Calcolo della matrice degli archi con p_val (fornito come parametro
     // dall'utente) che è la soglia minima. 
     if (mutual_info || k_cross) {
       mutualMat = buildMmatr(*db);
       SkelMat =  buildSkeleton(p_val, mutualMat);
		 }
     

     /** ******************* ATTENZIONE! *************************
         TUTTA la parte vecchia sull'ordinamento dei nodo è nel file oldmbn_evo.cpp */ 

    // ********** Si generano due oggetti della classe Multi_population. *** 

    // Si genera la popolazione iniziale.
    curr_pop = new Multi_population(N_inds, this);

    // Adesso si genera la popolazione iniziale.
    curr_pop->breed();


    /* Si genera un altro oggetto della classe Multi_population, inizialmen-
       te vuoto, da utilizzare come contenitore della popolazione alla gene-
       razione successiva.*/

    next_pop = new Multi_population(N_inds, this);


    return;
  }



  /*
  ----------------- procedura termination ---------------------------
  *** Scritta il:
  Controlla se sono verificati i criteri di terminazione dell'algori-
  tmo. QIn questo specifico caso questi criteri sono:
      - massimo numero di iterazioni;
      - la fitness del best_so_far e' nulla.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  bool Multi_evolution::termination()
  {
   if ((iters_done == N_iters) || (best_so_far->give_fitness() <= target_fit))
   {
     // Si visualizza il miglior individuo trovato.
     if (visual)
     {
       cout<<endl<<"iterazione: "<<iters_done<<endl;
       cout<<endl<<"il miglior individuo trovato e':"<<endl;
       best_so_far->show(&cout);
     }

     return true;
   }
   else return false;
  }

  
	/*
  ----------------- Procedura extract_param -----------------------------
  *** Scritta il:
  Estrae dalla linea in input il parametro contenuto e lo assegna al re-
  lativo attributo.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  bool Multi_evolution::extract_more_param(char *line)
  {
     char *line_ptr;

     /* Si convertono i minuscolo tutti i caratteri presenti nella linea
        passata come parametro. */
     str_lwr(line, MAX_CHAR_LINE);


     // ***************** Densita del grafo *************************
     if (strstr(line,(char *) "density"))
       if (get_double(line, (char *) "density", density))
          return true;
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"density\"!");

     // ***************** Numero di nodi del grafo *********************
     if (strstr(line, (char *) "n_nodes"))
       if (get_int(line, (char *) "n_nodes", N_nodes))
          return true;
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"nodes\"!");

     // ***************** Numero massimo di genitori *********************
     if (strstr(line, (char *) "max_pars"))
       if (get_int(line, (char *) "max_pars", max_pars))
          return true;
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"max_pars\"!");

     // ********** Numero massimo di genitori per il nodo label **********
     if (strstr(line, (char *) "max_par_label"))
       if (get_int(line, (char *) "max_par_label", max_pars_label))
          return true;
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"max_pas_label\"!");

     // ****** Numero massimo di nodi che hanno max_pars+1 genitori ******
     if (strstr(line, (char *) "max_bads"))
       if (get_int(line, (char *) "max_bads", max_bads))
          return true;
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"max_bads\"!");

     // ***************** fattore moltiplicativo per la complessit� *********
     if (strstr(line, (char *) "comb_fact"))
       if (get_double(line, (char *) "comb_fact", comb_fact))
          return true;
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"comb_fact\"!");

     /** ************************** FITNESS ***************************/
     // ***************** funzione di score grafo *********************
     if (strstr(line, (char *) "cpx")) {
       cpx = true;
       return true;
     }
		 // ***************** funzione di score grafo (2) *******************
     if (strstr(line, (char *) "mdl")) {
       mdl = true;
       return true;
     }
     /** ************************** OPERATORI *************************/
    // ***************** Probabilita di permutazione *****************
     if (strstr(line, (char *) "perm_prob"))
       if (get_float(line, (char *) "perm_prob", perm_prob)) {
         perm_mut = true; 
         return true;
       }
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"perm_prob\"!");
   
     // ***************** crossoover con conoscenza *******************
     if (strstr(line, (char *) "k_cross")) {
       k_cross = true;
       return true;
     }
     // ***************** micro mutazione *****************************
     if (strstr(line, (char *) "micro_mut")) {
       micro_mut = true;
       return true;
     }
   
     // ***************** fitness obiettivo *************************
     if (strstr(line, (char *) "target_fitness"))
       if (get_double(line, (char *) "target_fitness", target_fit))
          return true;
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"density\"!");
    
    // ***************** p value obiettivo *************************
     if (strstr(line, (char *) "p_value"))
       if (get_float(line,(char *) "p_value", p_val)) {
         mutual_info = true;      

         return true;
       }
       else abort_message((char *) "ERRORE ! Nella lettura del parametro \
		       \"p_value\"!");

     abort_message((char *) "ERRORE ! Nella lettura dei parametri! \
		           Questa linea e' sbagliata: %s\n", line);
  }


   inline  int Multi_evolution::comp_Mtx_diff(graph *dag)
  {
     int diff = 0;

     //WongMat->IsEqual2Mtx(dag->get_adj(), false, diff);// ??? 02.07.14

     return diff;
  }





  /*************************************************************************
          Definizione delle procedure della classe MULTI_POPULATION
   **********************************u**************************************/

  /*
  ----------------- Procedura Multi_Population -------------------------------
  *** Scritta il: 24/07/03
  E' la costruttrice della classe. E' vuota, il paramero N viene passato
  alla classe base.
  *** Ultima modifica:
  */
  Multi_population::Multi_population(int N, Evolution *evo_ptr) :
                    Population(N, evo_ptr)
  {

     return;
  }
  /*
  ----------------- Procedura Multi_population ----------------------------
  *** Scritta il: 24/07/03
  E' la procedura che general gli individui della popolazione iniziale.
  *** Ultima modifica:
  */
  void Multi_population::breed()
  {

     float den, comb_fact;
     int n_var, max_pars;
     bool cpx, mdl;


     // Si acquiscono i  valori di densita e numero di variabili.
     den   = ((Multi_evolution *) evolution)->give_density();
     n_var = ((Multi_evolution *) evolution)->give_node_num();


     // Si genera un numero di individui pari  a N_inds.
     for (ind_counter=0; ind_counter < N_inds; ++ind_counter)
     {
        // Si crea l'individuo.
	    individuals[ind_counter] = new Multi_individual(evolution);

	    /* Si costruisce una multilista random per l'individuo creato. Al
	       solito e' necessario il casting per chiamare le procedure speci-
	       fiche della classe Multi_individual. */
	   ((Multi_individual *) individuals[ind_counter])->build_multi(n_var, den);
     }


     // Si calcolano le fitness degli individui appena creati.
     comp_fitnesses();
     //exit(1);

     return;
  }

  /*
  ----------------- Procedura show_data ------------------------------------
  *** Scritta il:
  Mostra i dati specifici dell'iterazione appena eseguita.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  void Multi_population::show_data()
  {

     cout<<" fitness media: "<<average_fit<<" ****";


       cout<<endl<<" ****************** BEST ***************************** ";
       best->show(&cout);


     long int i;    // prova
     float tmp_avg, tmp=0.0;
     for (i=0; i < N_inds; ++i)
        tmp+= ((Multi_individual *) individuals[i])->length;


    tmp_avg = (float) tmp / N_inds;
    cout<<endl<<tmp_avg<<" "<<tmp<<" "<<N_inds;


   return;
  }


  /*************************************************************************
          Definizione delle procedure della classe MULTI_INDIVIDUAL
   ************************************************************************/



  /*
  ----------------- Procedura Multi_individual ----------------------------
  *** Scritta il: 24/07/03
  E' la procedura costruttrice della classe. Genera una multilista vuota
  *** Ultima modifica:
  */
  Multi_individual::Multi_individual()
  {
     int i;

     // Si inizializza la lunghezza dell'individuo.
     length = 0;

     return;
  }

/*
  ----------------- Procedura Multi_individual ----------------------------
  *** Scritta il: 24/07/03
  E' la procedura costruttrice della classe. Genera una multilista vuota
  *** Ultima modifica:
  */
  Multi_individual::Multi_individual(Evolution *e_ptr): Individual (e_ptr)
  {


     // Si inizializza la lunghezza dell'individuo.
     length = 0;


     // Si acquisiscono i parametri  x il calcolo della fitness.
     cpx              = ((Multi_evolution *) evo_ptr)->give_cpx();
     mdl              = ((Multi_evolution *) evo_ptr)->give_mdl();
     max_pars         = ((Multi_evolution *) evo_ptr)->give_max_pars();
     max_pars_label   = ((Multi_evolution *) evo_ptr)->give_max_pars_label();
     max_bads         = ((Multi_evolution *) evo_ptr)->give_max_bads();

     comb_fact        = ((Multi_evolution *) evo_ptr)->give_comb_fact();

     return;
  }


  /*
  ----------------- Procedura Multi_individual ----------------------------
  *** Scritta il: 24/07/03
  E' una terza procedura costruttrice della classe. Genera una multilista
  che codifica il grafo passato come parametro.
  *** Ultima modifica:

  Multi_individual::Multi_individual(graph *graph_ptr)
  {
     int i;


     // L'individuo e' vivo!
     alive = true;

     // Si inizializza la lunghezza dell'individuo.
     length = graph_ptr ->N_nodes;


     /* Si genera la multilista.
     for (i=1; i <= length; ++i)
        multi.push_back(Main_node(i, length - i, graph_ptr));

     return;
  }

  /*
  ----------------- procedura ~Multi_individual ---------------------------
  *** Scritta il:
  E' la distruttice della classe, in pratica, serve a cancellare la multi_
  lista dell'individuo.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */

  Multi_individual::~Multi_individual()
  {

     /* Si cancella la multilista con la procedura specifica della classe
        list. */
     multi.clear();

     length = multi.size();

     if (length > 0)
       delete [] scores;


     return;
  }




   /*
  ----------------- Procedura build_copy -----------------------------------
  *** Scritta il: 24/07/03
  Crea una copia di se' stesso e ne restituisce il puntatore.
  *** Ultima modifica:
  */
  Multi_individual *Multi_individual::build_copy()
  {
     Multi_individual *tmp_ptr;


     // Si alloca memoria per la copia.
     tmp_ptr = new Multi_individual();

     // Copia se' stesso nell'oggetto allocato.
     *tmp_ptr = *this;


     // Si ritorna il puntatore alla copia costruita.
     return tmp_ptr;
  }

  /*
  ----------------- Procedura giveActualMI --------------------------------
  *** Scritta il: 27/05/2011
  crea un vettore che per ogni elemento della main list ha associato il
  peso che ha nella main list in funzione dei collegamenti che ha con gli 
  altri nodi--> ossia ha la media delle MI link per link 
  -> il vettore in uscita � ordinato rispetto alla Adj e non alla ML!!!
  *** Ultima modifica:
  */
   vectr<float> *  Multi_individual::giveActualMI(matrx<int> & Adj)
   {
	   matrx<float> * sm = this->give_mutualMat();
	   int N_nodes = sm->get_column();
	   vectr<float> * actualMI=new vectr<float> ;
	   actualMI->initialize(N_nodes);
	   float app;

	   Adj.initialize(N_nodes,N_nodes);
	   
	   Multi_individual *tmp_ptr;

		register List<class Main_node>::iterator node_iter1, node_iter2;
		register List <class Link>::iterator link_iter;

		int i, node1, node2;
cout<<"main list:\n";
		for (node_iter1= multi.begin(); node_iter1 != multi.end(); ++node_iter1)
		{
			// Si memorizza la variabile contenuta nel nodo.
			node1 = node_iter1->val;
			
cout<<node1<<"\t";

			// Si inizializza il puntatore al nodo puntato da link.
			node_iter2 = node_iter1;

			// Si scorre la multilista per verificare a quali variabili � connessa.
			for (link_iter  = node_iter1->sub.begin();
				link_iter != node_iter1->sub.end(); ++link_iter)
			{
				// Si memorizza la variabile a cui punta il link.
				++node_iter2;
				node2 = node_iter2->val;

				// ******** Si memorizza nel grafo *****************
				// Si controlla prima se il link esiste.
				if (link_iter->val != NULL_LINK) // c'era l'uguale
				{
					Adj.put(node1, node2, 1);
				    Adj.put(node2, node1, -1);
				}
			}
		}

		cout<<"\nMatrice di adiacenza:\n";
		
		Adj.printmatrix();

		/*cout<<"Matrice di score:\n";		
		sm->printmatrix();*/


		for( node1=0; node1<N_nodes; node1++)
		{
			app=0;
			for(node2 =0 ; node2<N_nodes; node2++)
				if(Adj.get(node1,node2)!=0)
					app += sm->get(node1,node2);
			actualMI->put(node1,app);
		}
		
		//cout<<"vettore di score:\n";
		//actualMI->printvector();
		cout.flush();

     return actualMI;

   }
   /*
  ----------------- Procedura giveActualMI --------------------------------
  *** Scritta il: 27/05/2011
  crea un vettore che per ogni elemento della main list ha associato il
  peso che ha nella main list in funzione dei collegamenti che ha con gli 
  altri nodi--> ossia ha la media delle MI link per link 
  il vettore in uscita � ordinato secondo la ML
  *** Ultima modifica:
  */
   vectr<float>   Multi_individual::giveActualMI_MLsorted()
   {
	   int dim,i,node;
	   float val;
	   matrx<int> Adj;
	   vectr<float> * scoreVect, rank; 
	   
	   scoreVect = giveActualMI(Adj);
	   dim = scoreVect->get_lenght();
	   rank.initialize(dim);

	  
	  List<class Main_node>  multi_1 = this->multi;
	  register List<class Main_node>::iterator node_iter;
	

		i=0;
cout<<"\nmain list1 :\n";
		for (node_iter= multi_1.begin(); node_iter != multi_1.end(); ++node_iter)
		{
		
			node = node_iter->val;
			val = scoreVect->get(node);
			rank.put(i,val);
			i++;
			cout<<node<<"\t";

		}
		rank.printvector();

     return rank;

   }

 /*
  ----------------- Procedura giveActualMI --------------------------------
  *** Scritta il: 30/05/2011
  crea un vettore che per ogni elemento della main list ha associato il
  peso che ha nella main list in funzione dei collegamenti che ha con gli 
  altri nodi--> ossia ha la media delle MI link per link 
 la costruzione del vettore ordinato in base agli elementi della ML
� ottenuto le sub list di ogni nodo ossia non lavora pi� con la matrice Adj 
  *** Ultima modifica:
  */
   vectr<float>   Multi_individual::giveActualMIofMLelem()
   {
	   matrx<float> * sm = this->give_mutualMat();
	   int N_nodes = sm->get_column();
	   vectr<float> actualMI;
	   actualMI.initialize(N_nodes);

	   float app,v1;
		
	   vectr<float> scVect(N_nodes),scVe2(N_nodes),nodes(N_nodes);
	   	   
	   Multi_individual *tmp_ptr;

		register List<class Main_node>::iterator node_iter1, node_iter2;
		register List <class Link>::iterator link_iter;

		int i, j,node1, node2,k;
//cout<<"main list:\n";
i= 1;
		for (node_iter1= multi.begin(); node_iter1 != multi.end(); ++node_iter1)
		{
			// Si memorizza la variabile contenuta nel nodo.
			node1 = node_iter1->val;
			
//cout<<node1<<"\n";
			nodes.put(i-1,node1);

			// inizializza il puntatore al nodo puntato da link.
			node_iter2 = node_iter1;
				
			app=0;
			j=i;
			// Si scorre la multilista per verificare a quali variabili � connessa.
			for (link_iter  = node_iter1->sub.begin();
				link_iter != node_iter1->sub.end(); ++link_iter)
			{
				// Si memorizza la variabile a cui punta il link.
				++node_iter2;
				node2 = node_iter2->val;

				// ******** Si memorizza nel grafo *****************
				// Si controlla prima se il link esiste.

				if (link_iter->val != NULL_LINK) // c'era l'uguale
				{
					app = actualMI.get(j);
					app+= sm->get(node1,node2);
					actualMI.put(j,app);
					if(app>0)
					{
						scVect.initialize(N_nodes);
						for(k=j;k>=i;k--)
							scVect.put(k,app);

						//scVect.printvector();
						scVe2 = scVect + scVe2;
						//cout<<"scve2: ";
						//scVe2.printvector();
					}
					
				}
				j++;
				//actualMI.printvector();
			}
			
			i++;
			
		}
		
		
		/*cout<<"\n\nLa main list:";
		nodes.printvector();
		cout<<"forza dei collegamenti:";
		scVe2.printvector();
		
		cout.flush();*/

     return scVe2;

   }


    /*
  ----------------- Procedura computeWeight --------------------------------
  *** Scritta il: 30/05/2011
  assegna ad ogni elemento della MainList un peso corrisponente al 
  valore della MI che collega in nodo con gli altri della mainLIST
  fa riferimento sia agli archi entranti che a quelli uscenti 
  *** Ultima modifica:
  */
   void    Multi_individual::computeWeight(int cut)
   {
	   matrx<float> * sm = this->give_mutualMat();
	   int N_nodes = sm->get_column();
	   
	  
	   float app,v1;
	  
		
	   
	   	   
	   Multi_individual *tmp_ptr;

		register List<class Main_node>::iterator node_iter1, node_iter2;
		register List <class Link>::iterator link_iter;

		int i, j,node1, node2,k; 
		int contML,contSL;
//cout<<"main list:\n";

		i= 1;
		contML=0;
		for (node_iter1= multi.begin(); node_iter1 != multi.end(); ++node_iter1)
		{
			// Si memorizza la variabile contenuta nel nodo.
			node1 = node_iter1->val;
			contML++;


			// inizializza il puntatore al nodo puntato da link.
			node_iter2 = node_iter1;
				
			app=0;
			j=i;
			contSL=0;
			// Si scorre la multilista per verificare a quali variabili � connessa.
			for (link_iter  = node_iter1->sub.begin();
				link_iter != node_iter1->sub.end(); ++link_iter)
			{
				//  memorizza la variabile a cui punta il link.
				++node_iter2;
				node2 = node_iter2->val;
				contSL++;
				// ******** Si memorizza nel grafo *****************
				// Si controlla prima se il link esiste.
				
				if (link_iter->val != NULL_LINK) 
				{
					if(cut==0 || (contML+contSL)<=cut ||contML >cut)
					{
						node_iter1->weight+=sm->get(node1,node2);
						node_iter2->weight+=sm->get(node1,node2);
						
					}
					
					
				}
				j++;
				
			}
			
			i++;
			
		}
		
	
		/*for (node_iter1= multi.begin(); node_iter1 != multi.end(); ++node_iter1)
			cout << "nodoML: "<<node_iter1->pos<< " valore: "<<node_iter1->val<< " peso: "<<node_iter1->weight<<endl;
		
		cout.flush();*/

     

   }



   /*
  ----------------- Procedura copy_graph --------------------------------
  *** Scritta il: 24/07/03
  Crea una copia di se' stesso e ne restituisce il puntatore.
  *** Ultima modifica:
  */
  void Multi_individual::copy_graph(graph &g)
  {
     Multi_individual *tmp_ptr;

     register List<class Main_node>::iterator node_iter1, node_iter2;
     register List <class Link>::iterator link_iter;

     int i, node1, node2;

     for (node_iter1= multi.begin(); node_iter1 != multi.end(); ++node_iter1)
     {
        // Si memorizza la variabile contenuta nel nodo.
        node1 = node_iter1->val;

        // Si inizializza il puntatore al nodo puntato da link.
        node_iter2 = node_iter1;

        // Si scorre la multilista per verificare a quali variabili � connessa.
        for (link_iter  = node_iter1->sub.begin();
             link_iter != node_iter1->sub.end(); ++link_iter)
        {
           // Si memorizza la variabile a cui punta il link.
           ++node_iter2;
           node2 = node_iter2->val;

           // ******** Si memorizza nel grafo *****************
           // Si controlla prima se il link esiste.
           if (link_iter->val != NULL_LINK) // c'era l'uguale
           /*{
             g.put_edge(node1, node2, 0);
             g.put_edge(node2, node1, 0);
           }
           else  */
           {
             g.put_edge(node1, node2, 1);
          //   g.put_edge(node2, node1, -1);
           }
        }
     }

     return;
   }
  /*
  ----------------- Procedura write_pheno ----------------------------------
  *** Scritta il: 24/07/03
  Scrive il fenotipo partendo dal genotipo (la multilista). Al momento e'
  vuota.
  *** Ultima modifica:
  */
  void Multi_individual::write_pheno()
  {

     return;
  }



  /*
  ----------------- Procedura comp_fitness ---------------------------------
  *** Scritta il: 24/07/03
  Calcola la fitness dell'individuo.
  *** Ultima modifica:
  */
  double Multi_individual::comp_fitness()
  {
    register List<class Main_node>::iterator node_iter;
    register List <class Link>::iterator link_iter;
    int i, j, not_nulls;
    float score, comb_cpx;
  
   
   dag->reset(length);

   copy_graph(*dag);
  
  // bool MDL = <;
  // bool cpxMode = false;

// si controlla il vincolo del massimo numero di padri
   if (!dag->EVOCheckConstraint(max_pars, max_pars_label))
   {
     alive = false;
     if (mdl)
       fitness = 1000000;
     else fitness = -1000000;
     return fitness;
   }
	
   bn->initialize(*dag, *db);
 
  // bn->PrintGraph("E:\\SvnS\\private.scotto\\BayesianNetworks\\StructuralLearning\\EVOBN\\out.graph.dat");
 /*  cout<<"Tempo prima del learning parameter: "<<get_time()<<endl;
	bn->learning_parameter(*db,*dag); 
	//cout<<"Tempo dopo del learning parameter: "<<get_time()<<endl;
	bn->BNExternallyLearned();  	//bn->Serialize();
	fitness = bn->RecRate_0(db->get_D());
	cout<<"Tempo dopo calcolo del RR: "<<get_time()<<endl; */
  if(mdl)
  {
    /*inner_vars[0] = score = bn->MDLScore(*db, cpx);
    comb_cpx = comb_fact * dag->DeltaCpxSons(0);
    inner_vars[1] = comb_cpx;
    score += comb_cpx;
    fitness = score; */

    fitness = bn->MDLScore(*db, scores, cpx);
		
	

    float f, p = (float) evo_ptr->give_iters_done() /
                      evo_ptr->give_iters_num();

   f = fitness;

    if (false) {
              float *s = new float[length];
         for(i=0; i < length; ++i)
            s[i] = scores[i];


      if (get_best_parents()) {

      dag->reset(length);
      copy_graph(*dag);
      bn->initialize(*dag, *db);
      bn->BNExternallyLearned();

      fitness = bn->MDLScore(*db, scores);
      cout<<endl<<"prima: "<<f<<endl;

      for(i=0; i < length; ++i)
         cout<<i<<":"<<s[i]<<" ";
      cout<<endl<<" dopo: "<<fitness<<endl;
      for(i=0; i < length; ++i)
         cout<<i<<":"<<scores[i]<<" ";

       if (fitness < f)
        cout<<endl<<" better";
      else  if (f == fitness)
              cout<<endl<<" equal";
            else   cout<<endl<<" worse!!!"<<endl;

        delete [] s;

       for(i=0; i < length; ++i)
          sh[i] = false;
      }
//     cout<<"f: "<<f<<" fit:"<<fitness;
    }


//    fitness = ((Multi_evolution *) evo_ptr)->comp_Mtx_diff(dag);


  }
  else
  {
	score = bn->FastScore(*db, cpx);
	fitness = - score;
  }
//cout<<"Tempo dopo calcolo dello score: "<<get_time()<<endl;
   comp_time();

  /*cout<<endl<<"fitness: "<<fitness<<endl;
   for (node_iter = multi.begin(); node_iter != multi.end(); ++node_iter)
      cout<<node_iter->val+1<<" ";
*/

     return fitness;
  }


  /*
  ----------------- Procedura get_best_parents ---------------------------------
  *** Scritta il: 24/07/03
  Calcola la fitness dell'individuo.
  *** Ultima modifica:
  */


  bool Multi_individual::get_best_parents()
  {
     int i, ini_ptr;
     vectr<int> tmp;

     list<int>  ini_list;
     list<int>::iterator ini_iter;
     bool changed = false;

     // Si genera una lista di interi
     for(i=0; i< length; ++i)
         ini_list.push_back(i);

     cout<<endl<<"---------------- prima ----------------";
     show(&cout);
     cout<<endl<<endl<<".............nodi ............... ";
     for (i=0; i < length; ++i) {

        // Si sceglie un nodo in maniera random
        ini_ptr = rnd(0, ini_list.size() - 1);

       // Si punta l'elemento da inizializzare.
       ini_iter = ini_list.begin();
       advance(ini_iter, ini_ptr);

       if (bn->get_score(*ini_iter) != scores[*ini_iter])
         cout<<endl<<"AIUTO!!!!!!";

        if (give_min_score(*ini_iter) < scores[*ini_iter]) {
              //  cout<<endl<<"min:  "<<give_min_score(*ini_iter)<<" act: "
                //    <<scores[*ini_iter];                     */
//          tmp = bn->get_parents(*ini_iter);
          if (set_parents(*ini_iter))
            changed = true;
        }

	// Si cancella l'elemento dalla lista.
	ini_list.erase(ini_iter);

     }
     cout<<endl<<"----------------- dopo ----------------";
     show(&cout);
         cout<<endl<<"+++++++++++++++++++++++++++++++++++";

      return changed;
  }

  /*
  ----------------- Procedura set_parents ---------------------------------
  *** Scritta il: 24/07/03
  Calcola la fitness dell'individuo.
  ALGORITMO:
  1) DEVO SCORRERE LA LISTA FINO AD ARRIVARE AL NODO INTERESSATO
  2) a QUESTO PUNTO DEVO:
       a. trovare il nuovo padre + lontano verificando che non sia un figlio
       b. memorizzare anche i figli che si trovano nel frattempo.
       c. spostare tutti i figli dopo il nuovo padre + lontano
       d. aggoirnare tutti i padri.
  */
  bool Multi_individual::set_parents(int node)
  {
    int j;
    register List<class Main_node>::iterator first_iter, sec_iter, last_iter;
     register List<class Link>::iterator link_iter, *link_vec;
     bool ok = true;



     // Si scorre la multilista fino al nodo interessato. passo 1
     for (j=0, first_iter = multi.begin(); first_iter->val != node && (j < length -1);
          first_iter++, ++j)
        ;

     // Si controlla che non sia l'ultimo
     if (j < length -1)  {

       sec_iter = first_iter;
       ++sec_iter;
       last_iter = null_node;

       for (link_iter=first_iter->sub.begin();
            link_iter != first_iter->sub.end(); ++link_iter, ++sec_iter)
          if (is_father(node, sec_iter->val))
            if (link_iter->val == 1)
              return false;
	        else last_iter = sec_iter;

	   if (last_iter != null_node)
          ok = shift_node(multi, first_iter, last_iter,
                          bn->get_parents(node));
     }

     // SE � OK allora possiamo modificare i parents
     if (ok) {
         //cout<<endl<<"*********** dopo ************* ";
        // cout<<endl<<"first_it: "<<first_iter->val+1;
         //cout<<endl<<"last_it: "<<last_iter->val;
         vectr<int> tmp;
        cout<<endl<<" nodo:"<<node<<" score: "<<scores[node]<<" best_score: "<<
             give_min_score(node)<<" best: ";
        // cout<<endl<<"padri migliori:"<<endl;
         for (j=0; j < length; ++j)
            if (min_scores[node].pars[j])
              cout<<j<<" ";

              tmp = bn->get_parents(node);
              cout<<"attuali: ";
              for (j=0; j < tmp.get_lenght(); ++j)
                 cout<<tmp.get(j)<<" ";
        sh[node] = true;

       // Si scorre la multilista fino al nodo interessato.
       for (first_iter = multi.begin(); first_iter->val != node &&
            first_iter != multi.end();  first_iter++) {

	    sec_iter = first_iter;
	    ++sec_iter;

	    for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end();
                link_iter++, sec_iter++)
	       if (sec_iter->val == node)
		     if (is_father(node, first_iter->val))
		       link_iter->val = 1;
		   else link_iter->val = 0;
      }
      //show(&cout);
      //cout<<flush;
      return true;
     } else return false ;

}





  /*
  ----------------- Procedura comp_arcs ---------------------------------
  *** Scritta il: 24/07/03
  Calcola la fitness dell'individuo.
  *** Ultima modifica:
  */
  int Multi_individual::comp_arcs()
  {
    register List<class Main_node>::iterator node_iter;
    register List <class Link>::iterator link_iter;

    int arc_num;

    arc_num = 0;


   for (node_iter=multi.begin(); node_iter != multi.end(); ++node_iter)
      for (link_iter=node_iter->sub.begin(); link_iter!=node_iter->sub.end(); ++link_iter)
        if (link_iter->val == 1)
          ++arc_num;

return arc_num;


  }

  /*
  ----------------- procedura kill ----------------------------------------
  *** Scritta il:
  Serve a restituire al sistema la memoria utilizzata dall'individuo.
  *** Ultima modifica: ore 16.00 del 04/04/03
  */
  void Multi_individual::kill()
  {

     /* Cancella se stesso. chiamando il distruttore specifico della classe
        per la distruzione della multilista dell'individuo. */


     delete this;


     return;
  }

int n;
  /*
  ----------------- Procedura build_multi ----------------------------------
  *** Scritta il: 24/07/03
  Costruisce in maniera random la  multilista dell'individuo. Parametri:
  -- len: lunghezza della multilista;
  -- den: densita deegli archi;
  *** Ultima modifica:
  */
  void Multi_individual::build_multi(int len, float den)
  {
    List<class Main_node>::iterator node_iter;


    list<int>  ini_list;
    list<int>::iterator ini_iter;
    int i, tmp, ini_ptr;

    // Si inizializzano lunghezza e densita della multislista.
    length  = len;
    density = den;

    scores = new float[len];

    /* Generazione random della multilista. La main lista contiene una per-
       mutazione.  Si genera una lista che contiene una sequenza di valori
       da 1 a length. */
    for (i=0; i < length; ++i)
       ini_list.push_back(i);


    // Adesso si costruisce la multilista.
    for(i=0; i< length; ++i)
    {  // *************** VERSIONE STANDARD *****************************
       /* Si sceglie in maniera casuale un elemento della lista di inizi-
          alzzazione. */
       ini_ptr = rnd(0, ini_list.size() - 1);

       // Si punta l'elemento da inizializzare.
       ini_iter = ini_list.begin();
       advance(ini_iter, ini_ptr);

       /* Si assegna il valore puntato in ini_list all'elemento i-esimo
          della multilista. */
       multi.push_back(Main_node(*ini_iter, 0.0, i, length - i -1));

      /* Si cancella dalla lista di inizializzazione l'elemento appena in-
         serito. */
      ini_list.erase(ini_iter);

    }



   // matrx<float> *m = ((Multi_evolution *)evo_ptr)->give_mutualMat();

    //float t =  ((Multi_evolution *)evo_ptr)->give_threshold();

    /* float t_min, t_max;

    t_min = ((Multi_evolution *)evo_ptr)->give_min_thresh();
    t_max = ((Multi_evolution *)evo_ptr)->give_max_thresh();

    threshold= rndreal(t_min, t_max); */



    // Adesso di inseriscono gli archi
    bool **am = give_SkelMat();
 /*
    int j;
       for (i=0; i < 26; ++i) {cout<<endl<<i<<" : ";
          for (j=0; j < 26; ++j)
	     if (am[i][j])
	       cout<<" "<<j; else cout<<" *"; }
       //cout<<endl<<val+1<<" : ";
   */ n=0;
    for (i=0, node_iter = multi.begin(); i < length -1; ++i, node_iter++)
        node_iter->add_arcs(den); // ,  m, t, node_iter);
       //node_iter->add_arcs(den, am, node_iter);
    // Adesso si inserisce l'ultimo elemento rimasto.
   // ini_iter = ini_list.begin();
    // multi.push_back(Main_node(*ini_iter, density, i, length - i));
 //cout<<endl<<"n: "<<n;
   // show(&cout);

    return;
  }
  int find_max(matrx<float> *sm, bool *mst, bool *out, int N_nodes, int &mst_index);
  /*
  ----------------- Procedura build_multi ----------------------------------
  *** Scritta il: 24/07/03
  Costruisce in maniera random la  multilista dell'individuo. Parametri:
  -- len: lunghezza della multilista;
  -- den: densita deegli archi;
  *** Ultima modifica:
  */
  void Multi_individual::build_multi2(int len, float den)
  {
    List<class Main_node>::iterator node_iter;

   // matrx<float> *m = ((Multi_evolution *)evo_ptr)->give_mutualMat();
    bool  *mst, *out ;
    int i, j, mst_index, out_index;

     mst =  new bool[len];
     out =  new bool[len];
     scores = new float[len];


    // Si inizializzano lunghezza e densita della multislista.
    length  = len;
    density = den;


    for (i=0; i < len; ++i) {
       out[i] = true;
       mst[i] = false;
    }


    list<int>  ini_list;
    List<int>::iterator ini_iter;
    int  tmp, ini_ptr;

    /* for (i=0; i < length; ++i)
       ini_list.push_back(i);

    for(i=0; i< length; ++i)
    {
       /* Si sceglie in maniera casuale un elemento della lista di inizi-
          alizzazione. /
       ini_ptr = rnd(0, ini_list.size() - 1);

       // Si punta l'elemento da inizializzare.
       ini_iter = ini_list.begin();
       advance(ini_iter, ini_ptr);

       /* Si assegna il valore puntato in ini_list all'elemento i-esimo
          della multilista.
       multi.push_back(Main_node(*ini_iter, 0.0, i, length - i -1));

      /* Si cancella dalla lista di  inizializzazione l'elemento appena in-
         serito.
      ini_list.erase(ini_iter);
    }
    i = rnd(0, len-1);
    mst[i] = true;
    out[i] = false;

    multi.push_back(Main_node(i, 0.0, 0, length -1));
//    cout<<endl<<"*****************";
    for (i=1; i < len; ++i) {
       out_index = find_max(m, mst, out, len, mst_index);
       multi.push_back(Main_node(out_index, 0.0, i, length - i - 1));

  //   cout<<endl<<mst_index+1<<" -> "<<out_index+1<<";"<<flush;
       add_arc(mst_index, out_index);

       mst[out_index] = true;
       out[out_index] = false;
    }
  /*
    for (node_iter=multi.begin(); node_iter != multi.end(); ++node_iter)
       node_iter->add_arcs(0.01);

    */
    i=0;
    multi.push_back(Main_node(1-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(2-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(3-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(4-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(5-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(6-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(7-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(8-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(9-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(10-1,0.0,  i, length - i -1));++i;
    //multi.push_back(Main_node(11-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(12-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(13-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(14-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(15-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(16-1,0.0, i, length - i -1));++i;
     multi.push_back(Main_node(17-1,0.0, i, length - i -1));++i;

    multi.push_back(Main_node(11-1,0.0,  i, length - i -1));++i; // prova


    multi.push_back(Main_node(18-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(19-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(20-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(21-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(22-1,0.0,  i, length - i -1));++i;
    multi.push_back(Main_node(23-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(24-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(25-1,0.0, i, length - i -1));++i;
    multi.push_back(Main_node(26-1,0.0, i, length - i -1));


  //  show_graph(&cout);
   //cout<<"********************************************";
    delete [] mst;
    delete [] out;



add_arc(1-1, 4-1);
add_arc(2-1, 4-1);
add_arc(3-1,4-1);
add_arc(3-1,6-1);
add_arc(4-1, 6-1);
add_arc(5-1, 6-1);
add_arc(6-1, 10-1);
add_arc(7-1,10-1);
add_arc(8-1,10-1);
add_arc(9-1,10-1);
add_arc(10-1,17-1);
add_arc(11-1,17-1);
add_arc(12-1, 20-1);
add_arc(13-1,20-1);
add_arc(14-1,18-1);
add_arc(15-1,18-1);
add_arc(16-1,18-1);
add_arc(17-1,21-1);
add_arc(18-1,21-1);
add_arc(19-1,21-1);
add_arc(20-1,21-1);
add_arc(21-1,25-1);
add_arc(22-1,25-1);
add_arc(23-1,25-1);
add_arc(24-1,25-1);
add_arc(25-1,26-1);

// Added
//add_arc(10-1,11-1);

 // comp_fitness();
 // cout.precision(20);
 //cout<<endl<<"fit: "<<fitness;
 // show(&cout);
 // exit(0);
  return;
  }



  /*
  ----------------- Procedura show -----------------------------------------
  *** Scritta il: 01/03/04
  E' la procedura che visualizza gli attributi dell'individuo.
  *** Ultima modifica:
  */
  void Multi_individual::show(ostream *out_stream)
  {
   int i;
   List<class Main_node>::iterator iter;
   bool others;

   // Inizializzazione
   others = true;

#ifdef REC_RATE_flag


   //Classificazione
   float RR_TR=0,RR_TS=0;

   dag->reset(length);
   copy_graph(*dag);


	bool OnlyLinked=false;


	if(OnlyLinked)
		bn->EnableMjVOptStricty2Liked();
	else
		bn->EnableMjVOpt();


   bn->initialize(*dag,*db);
   bn->learning_parameter(*db,*dag);
   bn->BNExternallyLearned();

   //n_run=n_run+1;
   bn->Serialize(n_run);

   int N, NS, N2, NS2;

   // ************************* TRAINING ************************
   // Acquiszione del numero di righe e colonne dei dataset
   N  = db->getN();
   NS = db->getNS();

  // si dichiariano le matrici 
   matrx<int> m(NS, N);
   
   // Si caricano le matrici
   m  = db->getD();
   
   // apprendimento sul train set
   RR_TR= bn->RecRateJoint(m);

   // ************************* TEST   ************************
    if (test_data) {
   N2  = db2->getN();
   NS2 = db2->getNS();
   matrx<int> m2(NS2, N2);
   m2 = db2->getD(); 
   RR_TS= bn->RecRateJoint(m2);
   }
   
#endif 



   // Si mostra la fitness.
   *out_stream<<endl<<"Fitness: "<<fitness;
   *out_stream<<endl<<"time: "<<time<<" sec";
   *out_stream<<endl<<"tipo di fitness: ";
   if (mdl)
     *out_stream<<"mdl";
     else *out_stream<<"Heckerman";
   if (cpx)
     *out_stream<<" con calcolo della complessit�"<<endl;

//   *dag->adj()
   /************ Si mostra la multilista dell'individuo. ***********

   *out_stream<<endl<<" La multilista contiene "<<multi.size()<<" nodi"<<
                endl;

   // Si stampa un riferimento.
   *out_stream<<"       ";

   for(i=1; i <= multi.size(); ++i)
   {
       // Formattazione
       out_stream->setf(ios::left);
       out_stream->width(3);

       *out_stream<<i<<" ";
   }
   *out_stream<<endl;


   /*Si scandisce la multilista fino a quando ogni nodo non ha mostrato
     tutti i nodi. La variabile i indica la profondita' dei links da mos-
     trare.
   i=0;

   while (others)
   {
     others = false;

     out_stream->width(1);

     if (i == 0)
       *out_stream<<endl<<"nodi: ";
     else
     {
       // Formattazione
       out_stream->setf(ios::left);
       out_stream->width(2);

       *out_stream<<endl<<i<<"    ";
     }

     // Vengono mostrati i links di profondita' i.
     for (iter = multi.begin(); iter != multi.end(); ++iter)
     {
        *out_stream<<" ";
        /* Se c'e' almeno un nodo che ha mostrato un link la variabile
          others diventa true. In caso contrario others resta false e
          si esce dal ciclo while.
        if (iter->show_node(out_stream, i))
          others = true;
     }

     // Serve ad una migliore visualizzazione.
     if (i == 0)
       *out_stream<<endl;
     ++i;
   }

   /* Prima di terminare la procedura si va' a capo per consentire la visu-
      lizzazione completa della multilista. */
   *out_stream<<endl;


// **** Codifica per graphviz *********** *
    *out_stream<<endl<<"*** GRAPH-VIZ ENCODING "<<endl;
    show_graph(out_stream);
    *out_stream<<endl<<"**************************************"<<endl;


   dag->reset(length);
   copy_graph(*dag);

   *out_stream<<endl<<"*** matrice del grafo: "<<endl;
   dag->print_adj(*out_stream);
   *out_stream<<endl<<"score (fitness): "<<fitness;
//ALE 02.07.14 -- BEGIN

   float Bdeu=0,MDL=0,MDLc=0, bnBdeu=0,bnMDL=0,bnMDLc=0;


   
   bn->initialize(*dag,*db);
   bn->learning_parameter(*db,*dag);
   bn->BNExternallyLearned();
   bnBdeu= bn->score(*db);	
	bn->Serialize(n_run);
	bn->FreeCachedScore();
	bnMDL=bn->MDLScore(*db,false);	// MDL di wong con la complessità	
	bn->FreeCachedScore();
	bnMDLc= bn->MDLScore(*db,true);
	*out_stream<<"\n#####\n new printed data\n";
	*out_stream<<"BDeuScore:\t "<< bnBdeu<<"\n";
	*out_stream<<"MDLScore:\t "<< bnMDL<<"\n";
	*out_stream<<"MDL+cpx_score:\t "<< bnMDLc<<"\n";


   int NumDiff=0,missing=0, extra=0, reversed=0;
   int N2=dag->get_adj().get_row();
	matrx<int> WongMat(N2,N2);
	WongMat.LoadMtrxAdj("WongGraph.dat",Bdeu,MDL,MDLc);

	/*WongMat.printmatrix(cerr);
	cerr << "WongGraph.dat" <<endl;*/
	 *out_stream << "\nWongGraph.dat" <<endl;
	 *out_stream<<"BDeuScore:\t "<< Bdeu<<"\n";
	 *out_stream<<"MDLScore:\t "<< MDL<<"\n";
	 *out_stream<<"MDL+cpx_score:\t "<< MDLc<<"\n";	


	if (Bdeu!=0)
	{
		 *out_stream<<"\nDivergenze:\ndelta_BDeu = WongBdeu-bnBdeu = " << Bdeu<< " - ("<<bnBdeu <<") = \t"<< Bdeu-bnBdeu<< "\t("<<  (Bdeu-bnBdeu)/(Bdeu+bnBdeu) <<"%)\n";
		 *out_stream<<"delta_MDL = WongMDL-bnMDL = " << MDL << " - ("<< bnMDL <<") = \t"<<  MDL-bnMDL<< "\t ("<<  (MDL-bnMDL)/ (MDL+bnMDL)<<"%)\n";
		 *out_stream<<"delta_MDL+cmp = WongMDLc-bnMDLc = " << MDLc << " - ("<< bnMDLc <<") = \t"<<  MDLc-bnMDLc<< "\t ("<<  (MDLc-bnMDLc) /(MDLc+bnMDLc)<<"%)\n";
	}

	if(WongMat.IsEqual2AdjMtx(dag->get_adj(),NumDiff,missing, extra, reversed,false))
		*out_stream<<"NESSUNA DIFFERENZA STRUTTURALE\n";
		
	*out_stream<<	"Le matrici di adiacenza differiscono per N. archi: \t"<<NumDiff<<"\nmancanti: \t"<<missing<<"\nextra: \t"<<extra <<"\ninvertiti:\t "<< reversed;



//ALE 02.07.14 -- STOP
   *out_stream<<endl<<"**************************************"<<endl;


   return;
  }


 /*
  ----------------- Procedura show_graph ----------------------------------
  *** Scritta il: 01/03/04
  E' la procedura che visualizza il grafo rappresentato dall'individuo usa-
  ndo il programma graphviz.
  *** Ultima modifica:
  */
  void Multi_individual::show_graph(ostream *out_stream)
  {

     register List<class Main_node>::iterator node_iter1, node_iter2;
     register List <class Link>::iterator link_iter;

     int i, node1, node2;
int n=0;//se conto da 1 a N n=1 se conto i nodi da 0 a n-1 n=0/***********ALE

      // Si inizia tracciando il grafo.
     *out_stream<<endl<<"digraph Bayesian_network {";
     // Forma dei nodi
     *out_stream<<endl<<"node [shape = circle];";

     // Si scrivono i nodi da tracciare.
     for (node_iter1= multi.begin(); node_iter1 != multi.end(); ++node_iter1)
        *out_stream<<" "<<node_iter1->give_value()+n;
     // Si termina la lista dei nodi.
     *out_stream<<";";

     /** **************** Si tracciano gli archi *****************       */
     for (node_iter1= multi.begin(); node_iter1 != multi.end(); ++node_iter1)
     {
        // Si memorizza la variabile contenuta nel nodo.
        node1 = node_iter1->give_value();

        // Si inizializza il puntatore al nodo puntato da link.
        node_iter2 = node_iter1;

        // Si scorre la multilista per verificare a quali variabili è connessa.
        for (link_iter  = node_iter1->sub.begin();
             link_iter != node_iter1->sub.end(); ++link_iter)
        {
           // Si memorizza la variabile a cui punta il link.
           ++node_iter2;
           node2 = node_iter2->give_value();

           // ******** Si memorizza nel grafo *****************
           // Si controlla prima se il link esiste.
           if (link_iter->val != NULL_LINK)
           {
             *out_stream<<endl<<node_iter1->give_value()+n<<" -> ";
             *out_stream<<node_iter2->give_value()+n<<";";
           }
        }
     }

     // FINE del grafo.
     *out_stream<<endl<<"}";

     return;
  }




/*



  /*************************************************************************
          Definizione delle procedure della classe MAIN_NODE
   ************************************************************************/


  /*
  ----------------- Procedura Main_node ----------------------------------------
  *** Scritta il: 24/07/03
  E' la procedura costruttrice della classe. Genera un nodo vuoto e senza
  sottolista.
  *** Ultima modifica:
  */
  Main_node::Main_node()
  {

    return;
  }


  /*
  ----------------- Procedura Main_node -----------------------------------
  *** Scritta il: 01/03/04
  E' una seconda procedura costruttrice della classe. Genera un nodo as-
  segnandogli un valore casuale.  Il parametro position specifica la posi-
  zione del nodo all'interno della lista principale. Il sub_len specifica
  la lunghezza della sottolista da costruire.
  *** Ultima modifica:
  */
  Main_node::Main_node(int value, float den, int position, int sub_len)
  {
     int i, l_val;

     /* Si memorizza la posizione del nodo all'interno della lista princi-
        pale. */
     pos = position;

     // Si assegna il valore contenuto nella multilista.
     val =  value;

weight=0.0;//ALE 23/6/2011


      /* La lunghezza della sottolista da generare dipende sia dalla lungh-
         ezza  della multilista che dalla posizione del nodo all'interno
         della lista principale. */
     for(i=1; i <= sub_len; ++i)
     {
        // In base alla densita' si genera il valore da assegnare all'arco.
        if (flip(den))
          l_val = 1;
        else l_val = 0;

        sub.push_back(Link(i, l_val));
     }

     return;
  }



  /*
  ----------------- Procedura ~Main_node ----------------------------------
  *** Scritta il: 01/03/04
  E' la distruttice della classe, cancella la sua sottolista.
  *** Ultima modifica:
  */
  Main_node::~Main_node()
  {

    /* Si cancella la sottolista con la procedura specifica della classe
       List. */
    sub.clear();


    return;
  }
  /*
  ----------------- Procedura check_sub -----------------------------------
  *** Scritta il: 01/03/04
  Verifica l'esatta lunghezza della sottolista del nodo. Il parametro right_
  len specifica la lunghezza giusta per la sottolista.
  *** Ultima modifica:
  */
  void Main_node::check_sub(int right_len)
  {
     int i;


     // Si controlla se la lunghezza della sottolista e' quella giusta
     if (sub.size() == right_len)
       return;

     // Si controlla se e' piu' lunga. In tal caso la lista viene accorciata.
     if (sub.size() > right_len)
     {
       sub.resize(right_len, Link());

       return;
     }
     /* E' piu' corta, quindi deve essere allungata aggiungendo links che
        contengono il valore nullo. */
     for (i=sub.size()+1; i <= right_len; ++i)
        sub.push_back(Link(i, NULL_LINK));


     return;

  }

  /*
  ----------------- Procedura mutation ------------------------------------
  *** Scritta il: 01/03/04
  Serve ad applicare la mutazione al nodo e a tutti gli elementi della sua
  sottolista.
  *** Ultima modifica:
  */
  void Main_node::mutation(float prob)
  {
     register List<class Link>::iterator iter;
     int tmp_val;


     // Si scandisce la sottolista del nodo.
     for (iter = sub.begin(); iter != sub.end(); iter++)
        /* Secondo la probabilita' specificata si mutano i valori della sot-
          tolista. */
        if (flip(prob))
          if (iter->val == 0)
            iter->val = 1;
          else iter->val = 0;


     return;
  }

  /*
  ----------------- Procedura mutation ------------------------------------
  *** Scritta il: 01/03/04
  Serve ad applicare la mutazione a tutti gli elementi della sottolista
  *** Ultima modifica:
  */
  void Main_node::mutation(float prob, bool **am,
                           List<class Main_node>::iterator next_iter)
  {
     register List<class Link>::iterator link_iter;
     register List<class Main_node>::iterator node_iter;
     int tmp_val;
     float score;


     // Si controlla che ci sia almeno un nodo successivo.
     if (sub.size() > 0) {
       // Si inizializza l'iteratore ai nodi che seguono.
       node_iter = next_iter;
     } else return;


     // Si scandisce la sottolista del nodo.
     for (link_iter = sub.begin(); link_iter != sub.end(); link_iter++, node_iter++) {
        // Si verifica la mutua informazione.
	if (am[val][node_iter->val]|| am[node_iter->val][val])
	  //score =  sm->get(val, node_iter->val);
	  // Si muta secondo la probabilita' specificata
          if (flip(prob))
            if (link_iter->val == 0)
            link_iter->val = 1;
          else link_iter->val = 0;
     }

     return;
  }

  void move_node(List<class Main_node> &multi, int node, int shift);

  /*
  ----------------- Procedura shift_node ----------------------------------
  *** Scritta il: 01/03/04
  Serve a spostare un nodo all'interno della multilista per invertire un
  arco.
  *** Ultima modifica:
  */

  bool shift_node(List<class Main_node> &multi,
		 List<class Main_node>::iterator first_iter,
                 List<class Main_node>::iterator &second_iter, bool first)
  {
    register List<class Link>::iterator link_iter;
    register List<class Main_node>::iterator tmp_iter;



    int  pos, dist, num, sec_val;
    bool ok = true;


    link_iter = first_iter->sub.begin();
    tmp_iter = first_iter;
    ++tmp_iter;
    dist = distance(first_iter, second_iter);
    sec_val = second_iter->val;

    //while ((i < dist - 1) && ok)  {
    while (tmp_iter->val != sec_val  && ok)
      if (link_iter->val == 1)
	    ok = shift_node(multi, tmp_iter, second_iter, false);
      else {
      ++link_iter;
      ++tmp_iter;
      }



    if (!ok)
      return false;
    else if ((link_iter->val == 1) && (!first))
	   return false;


    pos = distance(multi.begin(), first_iter);
    dist = distance(first_iter, second_iter);

    // Si sposta il node dopo second iter
    move_node(multi, pos, dist);

    // Si decrementa l'iteratore che adesso � pi� vicino.
    second_iter--;

    return true;
}

/*
  ----------------- Procedura shift_node ----------------------------------
  *** Scritta il: 01/03/04
  Serve a spostare un nodo all'interno della multilista per invertire un
  arco.
  *** Ultima modifica:
  */

  bool shift_node(List<class Main_node> &multi,
		 List<class Main_node>::iterator first_iter,
                 List<class Main_node>::iterator &second_iter, vectr<int> pars)
  {
    register List<class Link>::iterator link_iter;
    register List<class Main_node>::iterator tmp_iter;



    int  pos, dist, num, sec_val;
    bool ok = true;


    link_iter = first_iter->sub.begin();
    tmp_iter = first_iter;
    ++tmp_iter;
    dist = distance(first_iter, second_iter);
    sec_val = second_iter->val;

    //while ((i < dist - 1) && ok)  {
    while (tmp_iter->val != sec_val  && ok)
      if (link_iter->val == 1)
	    if (!pars.is_in(tmp_iter->val))
          ok = shift_node(multi, tmp_iter, second_iter, pars);
        else return false;
      else {
        ++link_iter;
        ++tmp_iter;
      }



    if (!ok)
      return false;
    else if (link_iter->val == 1)
	   return false;


    pos = distance(multi.begin(), first_iter);
    dist = distance(first_iter, second_iter);

    // Si sposta il node dopo second iter
    move_node(multi, pos, dist);

    // Si decrementa l'iteratore che adesso � pi� vicino.
    second_iter--;

    return true;
}

/*
  ----------------- Procedura check_node ----------------------------------
  *** Scritta il: 01/03/04
  Serve a spostare un nodo all'interno della multilista per invertire un
  arco.
  *** Ultima modifica:
  */

  bool check_node(List<class Main_node> multi,
		 List<class Main_node>::iterator first_iter,
                 List<class Main_node>::iterator &second_iter, bool first)
  {
    register List<class Link>::iterator link_iter;
    register List<class Main_node>::iterator tmp_iter;



    int  pos, dist, num, sec_val;
    bool ok = true;


    link_iter = first_iter->sub.begin();
    tmp_iter = first_iter;
    ++tmp_iter;
    dist = distance(first_iter, second_iter);
    sec_val = second_iter->val;

    //while ((i < dist - 1) && ok)  {
    while (tmp_iter->val != sec_val  && ok)
      if (link_iter->val == 1)
        ok = check_node(multi, tmp_iter, second_iter, true);
      else {
      ++link_iter;
      ++tmp_iter;
      }



    if (!ok)
      return false;
    else if ((link_iter->val == 1) && (!first))
	   return false;


    //pos = distance(multi.begin(), first_iter);
    //dist = distance(first_iter, second_iter);

    // Si sposta il node dopo second iter
   // move_node(multi, pos, dist);

    // Si decrementa l'iteratore che adesso � pi� vicino.
    second_iter--;

    return true;
}


  /*
  ----------------- Procedura mutation ------------------------------------
  *** Scritta il: 01/03/04
  Serve ad applicare la mutazione al nodo e a tutti gli elementi della sua
  sottolista.
  *** Ultima modifica:
  *
  void Main_node::mutation(float prob, List<class Main_node> &multi,
			   List<class Main_node>::iterator this_iter)
  {
     register List<class Link>::iterator link_iter;
     register List<class Main_node>::iterator node_iter;
     int tmp_val;


     // Si controlla che ci sia almeno un nodo successivo.
     if (sub.size() > 0) {
       // Si inizializza l'iteratore ai nodi che seguono.
       node_iter = this_iter + 1;
     } else return;


     // Si scandisce la sottolista del nodo.
     for (link_iter = sub.begin(); link_iter != sub.end(); link_iter++, node_iter++)  {
           int node_val = node_iter->val;
           /* Secondo la probabilita' specificata si mutano i valori della sot-
              tolista.
           if (flip(prob))
             if (link_iter->val == 0) {// Arco MANCANTE
	       if (flip(0.5))
	        link_iter->val = 1;
	       else if (shift_node(multi, this_iter, node_iter))
                      add_arc (val, node_val);
		    else link_iter->val = 1;     // non � possibile invertire l'arco: si muta senza invertire.
             }
	     else if (flip(0.5)) // Arco PRESENTE
		    link_iter->val = 0;
		  else if (shift_node(multi, this_iter, node_iter))
	            add_arc (val, node_val);
             else link_iter->val = 0;
     }

     return;
  }


   /*
  ----------------- Procedura add_arc ------------------------------------
  *** Scritta il: 01/03/04
  Serve ad aggungere l'arco tra il nodo i e il nodo j
  *** Ultima modifica:
  */
  void Multi_individual::add_arc(int i, int j)
  {
    List<class Main_node>::iterator node_iter, node_iter2;
    List<class Link>::iterator link_iter;


    for(node_iter= multi.begin(); node_iter != multi.end(); ++node_iter)
       if ((node_iter->val == i) || (node_iter->val == j))
         break;



    node_iter2 = node_iter;
    advance (node_iter2, 1);


    for(link_iter = node_iter->sub.begin(); node_iter2 != multi.end(); ++link_iter,
        node_iter2++)
    {

      if ((node_iter2->val == i) || (node_iter2->val == j)) {
        link_iter->val = 1;
        break;
      }
    }

    if (node_iter2 == multi.end())
      cout<<endl<<"ECCO!"<<flush;

    return;



  }
  /*
  ----------------- Procedura add_arcs ------------------------------------
  *** Scritta il: 01/03/04
  Serve ad applicare la mutazione a tutti gli elementi della sottolista
  *** Ultima modifica:

  void Main_node::add_arcs(float den, matrx<float> *sm, float threshold,
       List<class Main_node>::iterator node_iter)
  {
     register List<class Link>::iterator link_iter;
     //register List<class Main_node>::iterator node_iter;
     float score;

     // Si controlla che ci sia almeno un nodo successivo.
     if (sub.size() ==0)
       // Si inizializza l'iteratore ai nodi che seguono.
       //node_iter = next_iter;
       return;




     // Si scandisce la sottolista del nodo.
     for (link_iter = sub.begin(), ++node_iter; link_iter != sub.end(); link_iter++, node_iter++) {

        //if (val < node_iter->val )
	  score =  sm->get(val, node_iter->val);
	 //else  score =  sm->get(node_iter->val, val);
        // Si verifica la mutua informazione.

	if (score >= threshold)
          // Si muta secondo la probabilita' specificata
          if (flip(den))
            link_iter->val = 1;
          else link_iter->val = 0;
     }

     return;
  }
  */

  void Main_node::add_arcs(float den, bool **am, List<class Main_node>::iterator node_iter)
  {
     register List<class Link>::iterator link_iter;
     //register List<class Main_node>::iterator node_iter;


     // Si controlla che ci sia almeno un nodo successivo.
     if (sub.size() ==0)
       // Si inizializza l'iteratore ai nodi che seguono.
       //node_iter = next_iter;
       return;
    /*
       int i, j;
       for (i=0; i < 8; ++i) {cout<<endl<<i+1<<" : ";
          for (j=0; j < 8; ++j)
	     if (am[i][j])
	       cout<<" "<<j+1; else cout<<" *"; }
      // cout<<endl<<val+1<<" : ";

       */
       //cout<<endl<<val+1<<" : ";
     // Si scandisce la sottolista del nodo.

     for (link_iter = sub.begin(), ++node_iter; link_iter != sub.end(); link_iter++, node_iter++)
        // Si controlla  se l'arco pu� essere usato.
	  if (am[val][node_iter->val] || am[node_iter->val][val])
          // Si aggiunge secondo la probabilita' specificata
            if (flip(den))
             { link_iter->val = 1; ++n;} //cout<<" "<<node_iter->val+1;}
            else link_iter->val = 0;
       //} else cout<<"-"<<node_iter->val+1;
     // cout<<endl<<"-----------------------";

     return;
  }


  void Main_node::add_arcs(float den)
  {
    List<class Link>::iterator iter;



    for (iter=sub.begin(); iter != sub.end(); ++iter)
       if (flip(den))
         iter->val = 1;

    return;
  }

 /*
  ----------------- Procedura swap -----------------------------------
  *** Scritta il: 01/03/04
  Inverte gli attributi dei due archi passsati come parametri.
  *** Ultima modifica:
  */
 void Main_node::swap_arcs(int arc1, int arc2)
  {
     register List<class Link>::iterator iter, iter1, iter2;
     int i, tmp_val;

     iter1 = iter2 = null_link;

    if (arc1 >= arc2)
      cout<<endl<<"ATTENZIONE!: ERRORE IN Main_node::swap_arcs"<<flush;

     // Si scandisce la sottolista del nodo.
     for (iter = sub.begin(), i=0; iter != sub.end(); iter++, i++)
        // Si controlla se � uno degli archi da puntare.
        if (i == arc1) {
	  iter1 = iter;
	  break;
	}

      for ( ; iter != sub.end(); iter++, i++)
        // Si controlla se � uno degli archi da puntare.
        if (i == arc2) {
	  iter2 = iter;
	  break;
	}

	if ((iter1 != null_link) && (iter2 != null_link)) {
	  tmp_val = iter1->val;
	  iter1->val = iter2->val;
	  iter2->val = tmp_val;
	} else cout<<endl<<"ATTENZIONE!: ERRORE 2 in Main_node::swap_arcs"<<endl
	           <<flush;

     return;
  }

  /*
  ----------------- Procedura get_arc_value -------------------------------
  *** Scritta il: 01/03/04
  modifica il valore dell'arco passato come primo parametro con il  valore
  passato come secondo parametro.  La funzione restituisce  l vecchio valore
  contenuto nell'arco.
  *** Ultima modifica:
  */
  int Main_node::set_arc_value(int arc, int val)
  {
     register List<class Link>::iterator link_iter;
     int i, tmp_val;

     // Si punta all'arco
     for (i=0, link_iter = sub.begin(); (i < arc) && (link_iter != sub.end());
          ++i, ++link_iter)
        ;

     tmp_val = link_iter->val;
     link_iter->val = val;

     return tmp_val;
  }

  /*
  ----------------- Procedura show_node -----------------------------------
  *** Scritta il: 01/03/04
  Mostra il valore del nodo o di un elemento della sua sottolista.Il primo
  parametro specifica l'output, il secondo l'indice dell'elemento da visua-
  lizzare. Restituisce true se contiene un elemento di indice specificato
  dal parametro, false altrimenti.
  sottolista.
  *** Ultima modifica:
  */
  bool Main_node::show_node(ostream *out_stream, int index)
  {
     List<class Link>::iterator iter;

     // Si fissano i parametri di formattazione.
     out_stream->width(3);
     out_stream->setf(ios::left);

     // Si controlla se bisogna stampare il nodo.
     if (index == 0)
     {
       *out_stream<<val;

       return true;
     }

     if (index <= sub.size())
     {
       // Si inizializza l'iteratore.
       iter = sub.begin();

       // Si punta l'elemento da visualizzare.
       advance(iter, index - 1);

       // Si visualizza l'elemento.
       if (iter->val != 0)
       *out_stream<<iter->val;
       else *out_stream<<"*  ";

       return true;
     }

     /* La lista e' piu' corta dell'elemento cercato si restituisce false,
        dopo aver scritto un blank. */
     *out_stream<<" ";


     return false;
  }




  /*************************************************************************
          Definizione delle procedure della classe LINK
   ************************************************************************/

  /*
  ----------------- Procedura Link ----------------------------------------
  *** Scritta il: 24/07/03
  E' la procedura costruttrice della classe. Genera un elemento vuoto.
  *** Ultima modifica:
  */
  Link::Link()
  {

    return;
  }


  /*
  ----------------- Procedura Link ----------------------------------------
  *** Scritta il: 01/03/04
  E' una seconda procedura costruttrice della classe. Genera un elemento di
  una sottolista assengnadogli un valore random. Il parametro position spe-
  cifica la posizione dell'elemento all'interno della sottolista.
  *** Ultima modifica:
  */
  Link::Link(int position)
  {
     /* Si memorizza la posizione dell'elemento all'interno della sottolis-
        ta. */
     pos = position;

     /* Si memorizza il valore generato dalal procedura che genera un numero
        random per  la classe. */
     val = rnd(0,30);//give_val(); prova

     return;
  }

  /*
  ----------------- Procedura Link ----------------------------------------
  *** Scritta il: 01/03/04
  E' una terza procedura costruttrice della classe. Genera un elemento di
  una sottolista. Il primo parametro specifica la posizione dell'elemento
  all'interno della sottolista. Il secondo specifica il valore che il nodo
  deve assumere.
  *** Ultima modifica:
  */
  Link::Link(int position, int value)
  {
     /* Si memorizza la posizione dell'elemento all'interno della sottolis-
        ta. */
     pos = position;

     // Si memorizza il valore passato come parametro.
     val = value;


     return;
  }


  /*
  ----------------- Procedura ~Link ----------------------------------------
  *** Scritta il: 24/07/03
  E' la procedura distruttrice della classe. E' vuota.
  *** Ultima modifica:
  */
  Link::~Link()
  {


    return;
  }

  /*
  ----------------- Procedura give_val ------------------------------------
  *** Scritta il: 24/07/03
  Restituisce random uno dei valori che puo' essere assunto dal link.
  *** Ultima modifica:
  */
  int Link::give_val()
  {

    int tmp_val;
   // Prova x esperimenti.

  /* if (flip(0.5))
     tmp_val = rnd(val + 1, val + 4);
   else tmp_val = rnd(val - 4, val - 4);
   */ tmp_val = rnd(val - 1, val + 1);

   // Si controlla se il valore restituito e' all'interno del range.
   if ((tmp_val >= 0) && (tmp_val <= 30))
     return tmp_val;
   else if (tmp_val < 0)
          return tmp_val  + 30;
        else return tmp_val  - 30;
  }



  /*************************************************************************
          Definizione delle procedure della classe MULTI_CROSSOVER
   ************************************************************************/

  /*
  ----------------- Procedura Multi_crossover -----------------------------
  *** Scritta il: 24/07/03
  E' la costruttrice della classe, e' vuota.
  *** Ultima modifica:
  */
  Multi_crossover::Multi_crossover(Multi_evolution* evo_ptr)
  {
	  prob = evo_ptr->give_cross_prob();
    pHybridFlag = evo_ptr->is_k_cross();

  
    return;
  }


   /*
  ----------------- Procedura apply ---------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di crossover alle multiliste dei due individui passa-
  ti come parametri. Si costruiscono prima le copie deei due individui in
  in input e poi si applica l'operatore sulle copie. I puntatori alle copie
  cosi' modificate vengono memorizzate nei parametri output_ptr1 e
  output_ptr2.
  *** Ultima modifica:
  */
  void Multi_crossover::apply(Individual *input_ptr1, Individual *input_ptr2,
                                  Individual* &output_ptr1,
                                  Individual* &output_ptr2)
  {

    if ((input_ptr1 == NULL) || (input_ptr2 == NULL))
      abort_message((char *) "ERRORE!");
     

    /* Si effettua la copia dei primi due individui passati come parametri.
        Il casting e' necessario in quanto consente la chiamata della proce-
        dura specifica della classe Multi_individual. */
     output_ptr1  = ((Multi_individual *) input_ptr1)->build_copy();
     output_ptr2  = ((Multi_individual *) input_ptr2)->build_copy();

     // Lancio la monetina...
     if (flip(prob))
       // Crossover con conoscenza?
       if (pHybridFlag)
         crossM(output_ptr1, output_ptr2);
		   else cross(((Multi_individual *) output_ptr1)->multi,
                  ((Multi_individual *) output_ptr2)->multi);
     
 	
    return;
  }

  bool comp_diff(n_diff n1, n_diff n2)
{
   if (n1.d > n2.d)
     return true;
   else return false;
}

/*
  ----------------- Procedura apply ---------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di crossover alle multiliste dei due individui passa-
  ti come parametri. Si costruiscono prima le copie deei due individui in
  in input e poi si applica l'operatore sulle copie. I puntatori alle copie
  cosi' modificate vengono memorizzate nei parametri output_ptr1 e
  output_ptr2.
  *** Ultima modifica:
  */
  void Multi_crossover::apply(Individual *input_ptr1, Individual *input_ptr2,
                                  Individual* &output_ptr)
  {
    vector<n_diff> diffs;
    int i, len;
    n_diff tmp;
    Individual *tmp_ptr;

   if ((input_ptr1 == NULL) || (input_ptr2 == NULL))
     abort_message((char *) "ERRORE!");
     /* Si effettua la copia dei primi due individui passati come parametri.
        Il casting e' necessario in quanto consente la chiamata della proce-
        dura specifica della classe Multi_individual. */
     output_ptr  = ((Multi_individual *) input_ptr1)->build_copy();
     tmp_ptr  = ((Multi_individual *) input_ptr2)->build_copy();

     len = ((Multi_individual *) input_ptr1)->give_len();

     for (i=0; i < len; ++i) {
        tmp.number = i;
	tmp.d = ((Multi_individual *) input_ptr1)->give_score(i) -
	        ((Multi_individual *) input_ptr2)->give_score(i);

	diffs.push_back(tmp);
     }

     sort(diffs.begin(), diffs.end(), comp_diff);



     /* Si chiama la procedura della classe che effettua il crossover sulle
        muliliste delle copie appena costruite. Anche in questo caso e' ne-
        cessario il casting. Ovviamente, prima si lancia la monetina... */
     if (flip(prob))
       cross(((Multi_individual *) output_ptr)->multi,
            ((Multi_individual *) tmp_ptr)->multi);


   return;
  }
 int Multi_crossover::findCutPoint(Individual *output_ptr1, Individual *output_ptr2)
 {	 
	 int cut ,ind_counter,i;
	 bool esci=false;
	 float sector,arrow,max;
	 vectr<float> ScV1,ScV2,score,weakness;

	 ScV1 = ((Multi_individual *) output_ptr1)->giveActualMIofMLelem();					 
	 ScV2=((Multi_individual *) output_ptr2)->giveActualMIofMLelem();
	
	 score = ScV1 + ScV2;

	 ind_counter=score.get_lenght();
	
	 max = score.getMax();
	 weakness.initialize(ind_counter);
	  for (i=1; i < ind_counter; ++i){
		  weakness.put(i,max-score.get(i));
	  }
	  /*cout<< "\nForza delle main lists: ";
	  score.printvector();
	  cout<< "Weakness delle main lists: ";
	  weakness.printvector();*/
	 
	 //--------- Implementazione della ROULETTE WHEEL ----------------
	
	 sector = 0.0;

	/* assegna alla variabile arrow un numero tra 0.0 e 1.0 genera-
           to casualmente. */
     //arrow = rndreal(0.0, 1.0);

	 max = weakness.sumAll();
	 arrow = rndreal(0.1, max);


    // --- Implementazione della roulette wheel per MINIMIZZAZIONE --
     cut=0; 
	 for (i=0; i < ind_counter&& !esci; ++i)
	 {
		/*  controlla in quale "settore" della ruota e' finita la arrow */    
		
		 if (arrow == max)//1.0
		 {
				cut = ind_counter-1;
				esci=true;
		 }
		sector +=  weakness.get(i);
		if (arrow < sector)
		{	
			cut = i ;
			esci=true;
		}	
	 }

		return cut;
	}

 
  /*
  ----------------- Procedura cross ---------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di crossover alle multiliste passate come parametri.
  *** Ultima modifica:
  */
  void Multi_crossover::cross(List<class Main_node>  &multi_1,
                              List<class Main_node> &multi_2)
  {
     register List<class Main_node>::iterator iter1, iter2;
     int cut;

     register List<class Main_node> tmp_list;

	 // Si generano in maniera casuale i due punti di taglio.
     cut = rnd(1, multi_1.size() - 1);
	//cout<< "\nTAGLIO A "<<cut<<endl;

     /* I punti di taglio vengono generati in maniera tale che la lunghezza
        dei figli sia compresa nell'intervallo della lunghezza dei figli.
        A tale scopo si chiama la funzione give_cut della classe base. */
     //give_cut(multi_1.size(), multi_2.size(), cut1, cut2);

     // Si inizializzano gli iteratori.
     iter1 = multi_1.begin();
     iter2 = multi_2.begin();

     /* Adesso si puntano gli elementi cut-esimo della multiliste */
     advance(iter1, cut);
     advance(iter2, cut);


     /* Si taglia dalla prima multilista la parte che si trova dopo cut1 e
        la si memorizza nella multilista tmp_list. */
     tmp_list.splice(tmp_list.begin(), multi_1, iter1, multi_1.end());


     /* Si taglia dalla seconda multilista la parte che si trova dopo cut2 e
        la si appende alla multilista 1. */
     multi_1.splice(multi_1.end(), multi_2, iter2, multi_2.end());

     /* Si appende alla seconda multilista quella tagliata dalla prima mul-
        tilista e memorizzata in tmp_list. */
     multi_2.splice(multi_2.end(), tmp_list);


     /* Dopo l'applicazione del crossover si chiama la procedura che ripara
       le multiliste crossate. In odi non devono contenre valori ripetuti,
       perch�  rappresentano delle permutazioni.  */
    repair(multi_1, multi_2, cut);




     return;
  }

 
/*
  ----------------- Procedura repair --------------------------------------
  *** Scritta il: 01/03/04
  E' la procedura che verifica se la multilista e' completa e, in caso con-
  trario, la rende tale. /
  *** Ultima modifica:
  */
  void Multi_crossover::repair(List<class Main_node>  &multi_1,
                               List<class Main_node>  &multi_2, int cut)
  {
     register List<class Main_node>::iterator iter1, iter2, tmp_iter1,
					      tmp_iter2,                                            cut_iter1, cut_iter2 ;
     int val1, val2, pos1, pos2;

     // Si punta al punto del taglio sulla prima multilista.
     cut_iter1 =  multi_1.begin();
     advance(cut_iter1, cut);

     // Si ripete l'operazione sulla seconda multilista;
     cut_iter2 =  multi_2.begin();
     advance(cut_iter2, cut);


     for(iter1=multi_1.begin(); iter1 != cut_iter1; ++iter1)
     {
        // si memorizza il valore presente nel nodo.
        val1 = iter1->val;
        tmp_iter1 = null_node;
        tmp_iter1 = find_value(cut_iter1, multi_1.end(), val1);


		if (tmp_iter1 != null_node )
          for(iter2=multi_2.begin();iter2 != cut_iter2; ++iter2)
          {
             val2 = iter2->val;
	         tmp_iter2 = null_node;
             tmp_iter2 = find_value(cut_iter2, multi_2.end(), val2);

			 if (tmp_iter2->val == val2)
             { tmp_iter1->val = iter2->val;
               tmp_iter2->val = iter1->val;

	       break;
             }
           }

     }


     return;
  }
/*
  ----------------- Procedura crossM  --------------------------------------
  *** Scritta il: 31/05/11
  fa il crossover con unsando la MI dei nodi
  E' la procedura che verifica se la multilista e' completa e, in caso con-
  trario, la rende tale. e aggiusta anche nel caso di ripetizioni?? /
  *** Ultima modifica:
  */
  void Multi_crossover::crossM(Individual *output_ptr1, Individual *output_ptr2)
  {
     register List<class Main_node>::iterator iter1, iter2, tmp_iter1,
					      tmp_iter2, cut_iter1, cut_iter2 ;
	 List<class Main_node>  multi_1, multi_2,tmp_list;
     int val1, val2, pos1, pos2;
	 int cut;
      
	   /* // vecchio
	  //  generano in maniera casuale il punto di taglio.
	 //cut = rnd(1, multi_1.size() - 1);
	 
	 I punti di taglio vengono generati in maniera tale che la lunghezza
        dei figli sia compresa nell'intervallo della lunghezza dei figli.
        A tale scopo si chiama la funzione give_cut della classe base. */
     //give_cut(multi_1.size(), multi_2.size(), cut1, cut2);


	 cut = findCutPoint((Multi_individual *) output_ptr1,(Multi_individual *) output_ptr2);
	 //cout<< "\nTAGLIO nel punto : "<<cut <<"\n";
	 ((Multi_individual* )output_ptr1)->computeWeight(cut);
	 ((Multi_individual* )output_ptr2)->computeWeight(cut);

	multi_1= ((Multi_individual* )output_ptr1)->multi;
	multi_2= ((Multi_individual* )output_ptr2)->multi;

   

     //  inizializzo gli iteratori.
     iter1 = multi_1.begin();
     iter2 = multi_2.begin();

     /* Adesso si puntano gli elementi cut-esimo della multiliste */
     advance(iter1, cut);
     advance(iter2, cut);


     /*  taglia dalla prima multilista la parte che si trova dopo cut1 e
        la  memorizza nella multilista tmp_list. */
     tmp_list.splice(tmp_list.begin(), multi_1, iter1, multi_1.end());


     /*  taglia dalla seconda multilista la parte che si trova dopo cut2 e
        la  appende alla multilista 1. */
     multi_1.splice(multi_1.end(), multi_2, iter2, multi_2.end());

     /*  appende alla seconda multilista quella tagliata dalla prima mul-
        tilista e memorizzata in tmp_list. */
     multi_2.splice(multi_2.end(), tmp_list);

     
	 //  punta al punto del taglio sulla prima multilista.
     cut_iter1 =  multi_1.begin();
     advance(cut_iter1, cut);

     // Si ripete l'operazione sulla seconda multilista;
     cut_iter2 =  multi_2.begin();
     advance(cut_iter2, cut);

	

     for(iter1=multi_1.begin(); iter1 != cut_iter1; ++iter1)
     {
        //  memorizza il valore presente nel nodo.
        val1 = iter1->val;
        tmp_iter1 = null_node;
        tmp_iter1 = find_value(cut_iter1, multi_1.end(), val1);


		if (tmp_iter1 != null_node )//significa che ho una ripetizione
          for(iter2=multi_2.begin();iter2 != cut_iter2; ++iter2)//vado nella seconda ML
          {
             val2 = iter2->val;
	         tmp_iter2 = null_node;
             tmp_iter2 = find_value(cut_iter2, multi_2.end(), val2);//trovo la seconda ripetizione

			 if (tmp_iter2->val == val2)// � realmente una ripetizione? se si prima scambiavo brutalmente
             { 
				 float Hp1,Hp2;
				 Hp1 = iter1->weight + iter2->weight;
				 Hp2 = tmp_iter1->weight + tmp_iter2->weight;
				 if(Hp1>Hp2)
				 {
					 tmp_iter1->val = iter2->val;         	
					 tmp_iter2->val = iter1->val;
				 }
				 else
				 {
					 iter1->val = tmp_iter2->val;         	
					 iter2->val = tmp_iter1->val;
				 }
				 break;
             }
           }

     }

	((Multi_individual* )output_ptr1)->multi= multi_1;
	((Multi_individual* )output_ptr2)->multi= multi_2;


     return;
  }


  /*************************************************************************
          Definizione delle procedure della classe MULTI_MUTATION
   ************************************************************************/

  /*
  ----------------- Procedura Multi_mutation -------------------------------
  *** Scritta il: 24/07/03
  E' la costruttrice della classe, e' vuota.
  *** Ultima modifica:
  */
  Multi_mutation::Multi_mutation()
  {

    return;
  }



  /*
  ----------------- Procedura Multi_mutation -----------------------------
  *** Scritta il: 24/07/03
  E' una seconda costruttrice della classe, setta la probabilita' di appli-
  cazione della micro e della macro mutazione.
  *** Ultima modifica:
  */

  Multi_mutation::Multi_mutation(Multi_evolution* evo_ptr)
  {
     /* Per memorizzare la probabilita' di micromutazione si sfrutta l'at-
        tributo prob della classe base. */
     prob 		   = evo_ptr->give_mut_prob();
     perm_mut    = evo_ptr->is_perm_mut();
     perm_prob   = evo_ptr->give_perm_prob();
     micro       = evo_ptr->is_micro_mut();
     mutual_info = evo_ptr->is_mutual_info();

     // Si verifica se bisogna  generare lo skeleton della mutua informazione
     if (mutual_info)
       SkelMat = evo_ptr->give_SkelMat();

     else SkelMat = 0;

     return;
  }





  /*
  ----------------- Procedura apply ---------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione alla multilista dell'individuo passato
  come parametro. Si costruisce prima la copia dell'individuo in input e
  poi si applica l'operatore sulla copia. Il puntatore alla copia cosi' mo-
  dificata viene memorizzato nel parametro output_ptr.
  *** Ultima modifica:
  */
  void Multi_mutation::apply(Individual *input_ptr, Individual* &output_ptr)
  {
     /* Si costruisce la copia dell'individuo in input. Il casting e' ne-
       cessario, per effettuare la chaiamata specifica della classe Multi_
       individual. */


     output_ptr = ((Multi_individual *) input_ptr)->build_copy();

     // Si chiama la procedura di mutazione
     mutate(output_ptr);

     return;
   }

  /*
  ----------------- Procedura mutate ---------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione alla multilista dell'individuo passato
  come parametro. 
  *** Ultima modifica:
  */
  void Multi_mutation::mutate(Individual *input_ptr)
  {     

     /** ************* PERMUTAZIONE ***********************************/         
     // Si chiama prima la mutazione che permuta i nodi
       if (perm_mut)
         if (flip(perm_prob))
           per_ins(((Multi_individual *) input_ptr)->multi);

    /** ************* MUTAZIONE SUGLI ARCHI ***************************/   

    if (micro)       
			 micro_mut(((Multi_individual *) input_ptr)->multi);  
		// NUOVA mutazione
    else {
			float fract_prob, prob_count;

      fract_prob = modf(prob , &prob_count);

			if (flip(fract_prob))
        if (mutual_info)  
          ((Multi_individual *) input_ptr)->new_mut_skel(SkelMat);
        else ((Multi_individual *) input_ptr)->new_mut();
         
      
	    while (prob_count > 0.0) {
        if (mutual_info)  
          ((Multi_individual *) input_ptr)->new_mut_skel(SkelMat);
        else ((Multi_individual *) input_ptr)->new_mut();
		    prob_count -= 1.0;
		  }
    }
      
         

   return;
  }


  /*
  ----------------- Procedura apply ---------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione alla multilista dell'individuo passato
  come parametro, SENZA costruire la copia.
  *** Ultima modifica:
  */
  void Multi_mutation::apply(Individual* &input_ptr)
  {
    
    // Chiama la procedura di mutazione 
    mutate(input_ptr);

    return;
  }


  /*
  ----------------- Procedura per_mut ------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione della permutazione alla multilista passata
  come parametro.
  *** Ultima modifica:
  */
  void Multi_mutation::per_mut(List<class Main_node> &multi)
  {
     register List<class Main_node>::iterator iter1, iter2;
     int m_len, node1, node2, tmp;

     // S memorizza la lunghezza della multilista.
     m_len = multi.size();

     // Si scelgono due nodi in maniera random.
     node1 = rnd(0, m_len -1);
     node2 = rnd(0, m_len -1);

     if (node2 == node1)
       node2 = rnd(0, m_len -1);

     if (node2 > node1)
       swap_nodes(multi, node1, node2);
     else swap_nodes(multi, node2, node1);

     /* Si punta il primo nodo
      iter1 = multi.begin();
      advance(iter1, node1);

      // Si punta il secondo nodo
      iter2 = multi.begin();
      advance(iter2, node2);

      // Si scambiano i nodi.
      tmp = iter1->val;
      iter1->val = iter2->val;
      iter2->val = tmp;
     */

   return;
  }
 /*
  ----------------- Procedura per_mut2 -----------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione della permutazione alla multilista passata
  come parametro.
  *** Ultima modifica:
  */
  void Multi_mutation::per_mut2(List<class Main_node> &multi)
  {
     register List<class Main_node>::iterator iter1, iter2;
     int m_len, node1, node2, tmp;

     // S memorizza la lunghezza della multilista.
     m_len = multi.size();

     /* Si sceglie il primo nodo da permutare. Controllando prima
        la lunghezza della multilista. */
     if (m_len > 2)
       node1 = rnd(0, m_len -2);
     else {
       cout<<"ATTENZIONE!: ERRORE in Multi_mutation::per_mut2"<<endl<<flush;
       return;
     }

     node2 = node1 + 1;

     swap_nodes(multi, node1, node2);


      // *********************** VECCHIA PERMUTAZIONE ****************************
     /* Si sceglie il secondo nodo.
     if (node1 < m_len -1)
       node2 = node1 +1;
     else node2 = 0;


     // Si punta il primo nodo
      iter1 = multi.begin();
      advance(iter1, node1);

      // Si punta il secondo nodo
      iter2 = multi.begin();
      advance(iter2, node2);

      // Si scambiano i nodi.
      tmp = iter1->val;
      iter1->val = iter2->val;
      iter2->val = tmp; */


   return;
  }


    /*
  ----------------- Procedura per_ins -----------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione della permutazione alla multilista passata
  come parametro.
  *** Ultima modifica:
  */
  void Multi_mutation::per_ins(List<class Main_node> &multi)
  {

     int m_len, node, shift, os;

     // S memorizza la lunghezza della multilista.
     m_len = multi.size();


     /* Si sceglie il primo nodo da permutare. Controllando prima
        la lunghezza della multilista. */
     if (m_len > 2)
       node = rnd(0, m_len -1);
     else {
       cout<<"ATTENZIONE!: ERRORE in Multi_mutation::per_ins"<<endl<<flush;
       return;
     }


     shift = rnd(1, m_len - 1);

     if (node + shift  < m_len)
       move_node(multi, node, shift);
     else {
       //cout<<endl<<"***********";
       //cout<<endl<<"ins1  n: "<<node<<" s:"<<shift;
       os = (node + shift) - m_len;
       shift = os - node;
       //cout<<endl<<"ins2 node:"<<node<<" shift:"<<shift;
       move_node(multi, node, shift);
       //cout<<endl<<"***********";
     }



   return;
  }

/*
  ----------------- Procedura micro_mut ------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione della permutazione alla multilista passata
  come parametro.
  *** Ultima modifica:

 void Multi_mutation::micro_mut(List<class Main_node> &multi, bool **am)
  {
     register List<class Main_node>::iterator iter;
     int i, len;


     len = multi.size();
      // VECCHIA VERSIONE
      /* Si scandisce la multilista, chiamando la procedura di micromutazione
        per ogni nodo, la quale modifica solo i valori deli link. 
     for (i=0, iter=multi.begin(); i < len -1; ++i)
	    iter->mutation(prob, am , ++iter);



   return;
  }



/*
  ----------------- Procedura micro_mut ------------------------------------
  *** Scritta il: 01/03/04
  Applica l'operatore di mutazione della permutazione alla multilista passata
  come parametro.
  *** Ultima modifica:
  */
  void Multi_mutation::micro_mut(List<class Main_node> &multi)
  {
     register List<class Main_node>::iterator iter;
		 int i, len;
     
      // numero di nodi
			len = multi.size();

     if (mutual_info)
       for (i=0, iter=multi.begin(); i < len -1; ++i)
	        iter->mutation(prob, SkelMat, ++iter);
     else for (iter= multi.begin(); iter!=multi.end();  ++iter)
						 iter->mutation(prob);
     
     return;
  }

  /*
  ----------------- Procedura new_mut ------------------------------------
  *** Scritta il: 01/03/04
  Nuova versione, che applica la mutazione che effettua anche l'ordinamento
  *** Ultima modifica:
  */
  void Multi_individual::new_mut()
  {
      register List<class Main_node>::iterator first_iter, sec_iter;
      register List<class Link>::iterator link_iter;


      int arc, arc_counter, first_val, sec_val, j;


      arc = rnd(0, (length *(length-1))/2 - 1); // Si seleziona un arco in maniera random

      if (arc == 0){
        first_iter = multi.begin();
        sec_iter = first_iter;
	++sec_iter;
	first_val = first_iter->val;
	sec_val   = sec_iter->val;
	link_iter = first_iter->sub.begin();
      }
      else for (arc_counter=0, j=0, first_iter = multi.begin(); (j < length -1)
           &&  (arc_counter < arc); first_iter++, ++j) {
	      sec_iter = first_iter;
	      ++sec_iter;
	      //first_val = first_iter->val;
	      //sec_val = sec_iter->val;


	      for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end() &&
		  arc_counter < arc;  link_iter++, arc_counter++, sec_iter++)
		  ;
		// sec_val = sec_iter->val;
      }

      if (first_iter != multi.begin())
        --first_iter;
     if (link_iter == first_iter->sub.end()) {
       first_iter++;
       sec_iter = first_iter;
       ++sec_iter;
       link_iter = first_iter->sub.begin();
     }

       first_val = first_iter->val;
       sec_val = sec_iter->val;


      if (link_iter->val == 0)  // Arco MANCANTE
			if (flip(0.5))
				link_iter->val = 1;
			else if (shift_node(multi, first_iter, sec_iter, true))
               add_arc(first_val, sec_val);
			else link_iter->val = 1;     // non � possibile invertire l'arco: si muta senza invertire.
      else if (flip(0.5)) // Arco PRESENTE
	     link_iter->val = 0;
	   else if (shift_node(multi, first_iter, sec_iter, true))
                  add_arc (first_val, sec_val);
       else link_iter->val = 0;


     return;
  }

 // /*
 // ----------------- Procedura micro_mut ------------------------------------
 // *** Scritta il: 20/05/11 Ale
 // Nuova versione, che applica la mutazione che effettua anche l'ordinamento
 // *
 // */
 // void Multi_individual::new_mut(float perm_prob)
 // {
 //     register List<class Main_node>::iterator first_iter, sec_iter;
 //     register List<class Link>::iterator link_iter;


 //     int arc, arc_counter, first_val, sec_val, j;


 //     arc = rnd(0, (length *(length-1))/2 - 1); // Si seleziona un arco in maniera random



 //     if (arc == 0){
 //       first_iter = multi.begin();
 //       sec_iter = first_iter;
	//++sec_iter;
	//first_val = first_iter->val;
	//sec_val   = sec_iter->val;
	//link_iter = first_iter->sub.begin();
 //     }
 //     else for (arc_counter=0, j=0, first_iter = multi.begin(); (j < length -1)
 //          &&  (arc_counter < arc); first_iter++, ++j) {
	//      sec_iter = first_iter;
	//      ++sec_iter;
	//      //first_val = first_iter->val;
	//      //sec_val = sec_iter->val;


	//      for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end() &&
	//	  arc_counter < arc;  link_iter++, arc_counter++, sec_iter++)
	//	  ;
	//	// sec_val = sec_iter->val;
 //     }

 //     if (first_iter != multi.begin())
 //       --first_iter;
 //    if (link_iter == first_iter->sub.end()) {
 //      first_iter++;
 //      sec_iter = first_iter;
 //      ++sec_iter;
 //      link_iter = first_iter->sub.begin();
 //    }

 //      first_val = first_iter->val;
 //      sec_val = sec_iter->val;


 //     if (link_iter->val == 0)  // Arco MANCANTE
	//		if (flip(perm_prob))
	//			link_iter->val = 1;
	//		else if (shift_node(multi, first_iter, sec_iter, true))
 //              add_arc(first_val, sec_val);
	//		else link_iter->val = 1;     // non � possibile invertire l'arco: si muta senza invertire.
 //     else if (flip(perm_prob)) // Arco PRESENTE
	//     link_iter->val = 0;
	//   else if (shift_node(multi, first_iter, sec_iter, true))
 //                 add_arc (first_val, sec_val);
 //      else link_iter->val = 0;


 //    return;
 // }



  iters Multi_individual::give_iters(bool **am)
  {
      int j, arc, first_val, sec_val;
      register List<class Main_node>::iterator first_iter, sec_iter;
      register List<class Link>::iterator link_iter;


      list<iters> l;
      iters tmp_it;


      for (j=0, first_iter = multi.begin(); j < length -1; first_iter++, ++j) {
	      sec_iter = first_iter;
	      ++sec_iter;
	      first_val = first_iter->val;

	      for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end();                     	link_iter++, sec_iter++)
		 if (am[first_val][sec_iter->val] || am[sec_iter->val][first_val])
		 {
		   tmp_it.f = first_iter;
		   tmp_it.s = sec_iter;
		   tmp_it.l = link_iter;
		   l.push_back(tmp_it);
		 }
		  // cout<<endl<<first_val+1<<" "<<sec_iter->val+1<<flush;
      }

      register List<class iters>::iterator it;

      arc = rnd(0, l.size() - 1);

      it = l.begin();
      advance(it, arc);


      return *it;
  }

   /*
  ----------------- Procedura new_mut_skel -------------------------------
  *** Scritta il: 01/03/04
  Applica la new mut allo skeleton generato dalla mutua informazione, passato
  come primo parametro.
  *** Ultima modifica:
  */
  void Multi_individual::new_mut_skel(bool **am)
  {
    iters tmp_it;
    int first_val, sec_val;

    tmp_it = give_iters(am);
    first_val = tmp_it.f->val;
    sec_val = tmp_it.s->val;

   // cout<<endl<<first_val+1<<" - "<<sec_val+1;
    if (!am[first_val][sec_val] && !am[sec_val][first_val]){
      cout<<endl<<"ATTENZIONE!: errore in new_mut!!!";
      return;
    }


     if (tmp_it.l->val == 0)  // Arco MANCANTE
       if (flip(0.5))
	       tmp_it.l->val = 1;
	     else if (shift_node(multi, tmp_it.f, tmp_it.s, true))
              add_arc(first_val, sec_val);
	          else tmp_it.l->val = 1;   /* non è possibile invertire l'arco: si muta senza
                                         invertire. */
     else if (flip(0.5)) // Arco PRESENTE
	          tmp_it.l->val = 0;
	        else if (shift_node(multi, tmp_it.f, tmp_it.s, true))
                  add_arc (first_val, sec_val);
               else tmp_it.l->val = 0;

     return;


  }


  int Multi_individual::comp_arcs(bool **am)
  {
      int j, arc_counter, first_val, sec_val;
      register List<class Main_node>::iterator first_iter, sec_iter;
      register List<class Link>::iterator link_iter;



      for (arc_counter=0, j=0, first_iter = multi.begin(); j < length -1;
           first_iter++, ++j) {
	      sec_iter = first_iter;
	      ++sec_iter;
	      first_val = first_iter->val;

	      for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end();                     	link_iter++, sec_iter++)
		 if (am[first_val][sec_iter->val] || am[sec_iter->val][first_val])
		   ++arc_counter;
		  // cout<<endl<<first_val+1<<" "<<sec_iter->val+1;

      }

      return arc_counter;
  }

/*

  void Multi_individual::new_mut(bool **am, int num)
  {
      register List<class Main_node>::iterator first_iter, sec_iter;
      register List<class Link>::iterator link_iter;

      int arc, arc_counter, first_val, sec_val, j;

      num = comp_arcs(am);
      arc = rnd(0, num - 1); // Si seleziona un arco in maniera random

      /*int i;
       for (i=0; i < 8; ++i) {cout<<endl<<i+1<<" : ";
          for (j=0; j < 8; ++j)
	     if (am[i][j])
	       cout<<" "<<j+1; else cout<<" *"; }
          cout<<endl<<endl;
	 FINE COMMENTO
      if (arc == 0){
	first_iter = multi.begin();
	sec_iter = first_iter;
	++sec_iter;
        first_val = first_iter->val;

        for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end();  link_iter++,  sec_iter++)
	   if (am[first_val][sec_iter->val] || am[sec_iter->val][first_val])
	     break;
      }
      else for (arc_counter=0, j=0, first_iter = multi.begin(); (j < length -1)
           &&  (arc_counter < arc); first_iter++, ++j) {
	      sec_iter = first_iter;
	      ++sec_iter;
	      first_val = first_iter->val;

	      for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end() &&
		  arc_counter < arc;  link_iter++, sec_iter++)
		 if (am[first_val][sec_iter->val] || am[sec_iter->val][first_val])  {
		   ++arc_counter;
		   if (arc_counter == arc)
		     break;
		  // cout<<endl<<first_val+1<<" "<<sec_iter->val+1;
		  }
      }

      if (first_iter != multi.begin())
        --first_iter;
/*
     if (link_iter == first_iter->sub.end()) { a1 = true;
       first_iter++;
       sec_iter = first_iter;
       ++sec_iter;

       for(link_iter=first_iter->sub.begin(); link_iter != first_iter->sub.end();  link_iter++,  sec_iter++)
	   if (am[first_iter->val][sec_iter->val])
	     break;
       }
      // FINE COMMENTO

       first_val = first_iter->val;
       sec_val = sec_iter->val;




       //cout<<endl<<first_val+1<<" - "<<sec_val+1;
       /*if (a0)
         cout<<" arc = 0";
       else if (a1)
              cout<<" arc = 1";
      FINE COMMENTO

      if (link_iter->val == 0)  // Arco MANCANTE
	if (flip(0.5))
	  link_iter->val = 1;
	else if (shift_node(multi, first_iter, sec_iter, true))
               add_arc(first_val, sec_val);
	     else link_iter->val = 1;   // non � possibile invertire l'arco: si muta senza invertire.
      else if (flip(0.5)) // Arco PRESENTE
	     link_iter->val = 0;
	   else if (shift_node(multi, first_iter, sec_iter, true))
                  add_arc (first_val, sec_val);
                else link_iter->val = 0;

     return;
  }




/*
  ----------------- Procedura find_value ----------------------------------
  *** Scritta il: 01/03/04
  E' la procedura che verifica se la multilista e' completa e, in caso con-
  trario, la rende tale.
  *** Ultima modifica:
  */
  List<class Main_node>::iterator find_value
                         (List<class Main_node>::iterator start_iter,
                          List<class Main_node>::iterator end_iter,
                          int value)
  {
     register List<class Main_node>::iterator iter;

     // Inizializzazione

     for(iter=start_iter; iter != end_iter; ++iter)
        if (iter->val == value)
          return iter;

     return null_node;
  }

// **** DICHIARAZIONE delle funzioni load  ****
matrx<int> load(const char *file_name, int nodes, int samples);
matrx<int> load(const char *file_name, int nodes, int samples, int cols);

vectr<double> *LevelStat;
vectr<int> StatiNodi; 
/*
** test_name: nome del file di test
** ts: 	      numero di sample di test
** dp: 	      puntatore al database di test
*/
query_database *init(const char *test_name, int test_num, query_database* &dp)
{
int n,ns,i,j, val;
char *fileDB= (char *) "bn.dat";
char *fileConfig= (char *) "Config.dat";

fstream Cfdata(fileConfig);
   

        // ********* acuisizione file di configurazione ***********
	if(!Cfdata.is_open())
	{
		cerr<<"it's impossible to open the file:  "<< fileConfig <<endl;
		exit(1);
	}

	try{

		Cfdata>>n;// numero di variabili aleatorie
		Cfdata>>ns;// numero di campioni

	}catch(ios_base::failure)
	{
		int s = Cfdata.rdstate();
		if (s & ios::eofbit) cout << "Fine di cin" << endl;
		if (s & ios::failbit) cout << "Errore di lettura" << endl;
		exit(1);
	}
	if (n==0||ns==0)
	{
		cout <<"il file "<< fileConfig  <<"e' vuoto\n";
		exit(1);
	}


		int NumStatVar_i;
		double level_j;
		
		LevelStat = new vectr<double>[n];

		StatiNodi.initialize(n);
		NumStatVar_i=0;

		for (i=0;i<n;i++){

			try{
				Cfdata>>NumStatVar_i;

			}catch(ios_base::failure)
			{
				int s = Cfdata.rdstate();
				if (s & ios::eofbit) cout << "Fine di cin" << endl;
				if (s & ios::failbit) cout << "Errore di lettura" << endl;
				exit(1);
			}
			LevelStat[i].initialize(NumStatVar_i+1);
			StatiNodi.put(i,NumStatVar_i);

			for (j=0;j<NumStatVar_i+1;j++){

				try{
					Cfdata>>level_j;
				}catch(ios_base::failure)
				{
					int s = Cfdata.rdstate();
					if (s & ios::eofbit) cout << "Fine di cin" << endl;
					if (s & ios::failbit) cout << "Errore di lettura" << endl;
					exit(1);
				}
			LevelStat[i].put(j,level_j);
		}

	}

        Cfdata.close();
  // *******************

  query_database *db;
  matrx<int> tr_m, ts_m; // matrici per train e test set

  // si carica il train set (bn.dat)
  tr_m = load (fileDB, n, ns);
  db = new query_database(tr_m, StatiNodi);
  cout<<endl<<"fine bn.dat"<<flush; 
  // Si controlla se � stato passato il test_set
  if (dp != _dummy_query) {
    // si carica il test set (nome e numero sono passati da riga di comando)
    ts_m = load (test_name, n, test_num);
    dp = new query_database(ts_m, StatiNodi);
  }

  return db;	
}


 matrx<int> load(const char *file_name, int nodes, int samples){

    int i, j, val; 
   // vectr<double> *LevelStat;
   // LevelStat = new vectr<double>[n];
    fstream data(file_name);
		if(!data.is_open())
		{
			cerr<<"it's impossible to open the file:  "<< file_name <<endl;
			exit(1);
		}


		matrx<int> DataSet(nodes, samples);
		double LoadedVal;

		// dati Netica
		int cont;
		bool Netica= true;
		if(Netica)
		{
			char Intestazione[300];
			data.getline(Intestazione,300,'\n');
			//cout<< Intestazione<<endl;
		}


		for (j=0;j<samples;j++)
		{   
			if(Netica)
			{
				data >> cont; 
				if(cont!=j+1)
					; //cout<<"Attenzione "<<cont <<"  diverso da "<<j+1<<"\n";
			}
//cout<<endl<<j+1<<": "<<flush;
			for(i=0;i<nodes;i++)
			{
				try
				{
					data	>>	LoadedVal;
//cout<<LoadedVal<<" "<<flush;
				val		=	LevelStat[i].QuantizeVal(LoadedVal);

					DataSet.put(i,j,val);
				}
				catch(ios_base::failure)
				{
					int s = data.rdstate();
					if(s & ios::eofbit) cout << "Fine di cin" << endl;
					if(s & ios::failbit) cout << "Errore di lettura" << endl;
					exit(1);
				}

			}
		}
		data.close();

  return DataSet;
  }

 matrx<int> load(const char *file_name, int nodes, int samples, int cols){

    int i, j, val; 
    //vectr<double> *LevelStat;
  
    fstream data(file_name);
		if(!data.is_open())
		{
			cerr<<"it's impossible to open the file:  "<< file_name <<endl;
			exit(1);
		}


		matrx<int> DataSet(nodes, samples);
		double LoadedVal;

		// dati Netica
		int cont;
		bool Netica= true;
		if(Netica)
		{
			char Intestazione[300];
			data.getline(Intestazione,300,'\n');
			//cout<< Intestazione<<endl;
		}


		for (j=0;j<samples;j++)
		{
			if(Netica)
			{
				data >> cont;
				if(cont!=j+1)
					; //cout<<"Attenzione "<<cont <<"  diverso da "<<j+1<<"\n";
			}
//cout<<endl<<j+1<<": "<<flush;
			for(i=0;i<nodes;i++)
			{
				try
				{
					data	>>	LoadedVal;
//cout<<LoadedVal<<" "<<flush;
				val		=	LevelStat[i].QuantizeVal(LoadedVal);

					DataSet.put(i,j,val);
				}
				catch(ios_base::failure)
				{
					int s = data.rdstate();
					if(s & ios::eofbit) cout << "Fine di cin" << endl;
					if(s & ios::failbit) cout << "Errore di lettura" << endl;
					exit(1);
				}

			}
			int trash;
			for(i=0;i < cols-nodes;i++)
                        {
                                try
                                {
                                   data >> trash;
                                }
                                catch(ios_base::failure)
                                {
                                        int s = data.rdstate();
                                        if(s & ios::eofbit) cout << "Fine di cin" << endl;
                                        if(s & ios::failbit) cout << "Errore di lettura" << endl;
                                        exit(1);
                                }

                        }
		}
		data.close();

  return DataSet;
  }



bool comp_arc(arc a1, arc a2)
{
   if (a1.m > a2.m)
     return true;
   else return false;
}


/*bool is_in(int src_node, int dest_node, int max_pos, vector<arc> *mat)
bool is_in(int src_node, int dest_node,float p_val)
 {

   float m;

   if (src_node != dest_node) {
     m = Mutual(src_node,dest_node);

     if (m > p_val)
       return true;
     else return false;
   }

   return false;

   /*
   int i;
   for (i=0; i < max_pos; ++i)
      if (mat[src_node][i].number == dest_node)
        return true;

   return false;
}*/

  matrx<float> *buildMmatr(query_database &db)
  {
    matrx<float> *m;
    int i, j, n= db.getN();
    float val;

    // Allocazione di memoria per la matrice:
    m = new matrx<float>(n, n);

    for (i=0; i < n; ++i)
       for (j=i; j < n; ++j)
	        if (i != j) {
	          val = Mutual(i, j, db);
            cout<<endl<<i+1<<","<<j+1<<":"<<val<<flush;
            m->put(i, j, val);
            m->put(j, i, val);             
          } 
					else m->put(i, j, 0.0);

    return m;
  }

bool **buildSkeleton(float p_val, matrx<float> *m)
  {
    int i, j, n= m->get_row();
    bool **arcs;
    float val;
  
    // Allocazione di memoria per la matrice di bool:
    arcs = new bool*[n];
    for (i=0; i < n; ++i)
       arcs[i] = new bool[n];

    for (i=0; i < n; ++i)
       for (j=0; j < n; ++j)
	        if (i != j) {
	          val = m->get(i, j);	      
             if (val > p_val)
	             arcs[i][j] = true;
	           else arcs[i][j] = false;
          } else arcs[i][j] = false;

    return arcs;
  }



  matrx<float> G_statistics(query_database &db)
  {  
     int i,j, n=db.getN();
     float m, g;
     matrx<float> Gmat(n,n);


        int w = 0;

     for(i=0; i < n; ++i)
        for (j=0; j < n; ++j)
	if (i != j){
	   // Calcolo la mutua informazione.
	   m = Mutual(i,j,db);
	 /*  if (m > 0.30)
	   {cout<<endl<<i+1<<" "<<j+1; set_output((ofstream *) &cout, 10, 10);
	    cout<<" m_test:"<<m; ++w;
	     //cout<<endl;
	   // Calcolo la G del primo ordine.
	  // g = G_test(i,j,db);
	  }
	  //if (m > g) {
	     Gmat.put(i, j, m);
	    /* Gmat.put(j, i, m);
	   }
	   else {
	     Gmat.put(i, j, g);
	     Gmat.put(j, i, g);
	   }

	 // if(m < 0.95) {
	   cout<<endl<<i+1<<" "<<j+1<<flush;
	   cout<<" m: "<<m<<" g: "<<g;
	  // cout<<" "<<Gmat.get(i,j);
	 // }
	  */
	  
		Gmat.put(i, j,m); // ALessandra
	}  else
	  Gmat.put(i, j, 0.0);
	//cout<<endl<<"tot:"<<w<<endl; exit(0);

	 return Gmat;

  }


matrx<float> SeconOrderStatistic( query_database & db)
{
    int i,j, n=db.getN();

    matrx<float> ScoresXiXj(n,n);
    float val;

    ClassBN bTemp(n);
    graph g(n);
     cout<<endl;
    for(j=0;j<n;j++)
    {
	float valj =0;
        for(i=0;i<n;i++)
	if (i != j)
        {

            g.put_edge(j,i,1);
            bTemp.initialize(g,db);
            val = bTemp.MDLScore2(db, i);
	    float v2 = Mutual(i,j, db);
	    float v1 = Mutual(j,i, db);
	    float v3 = G_test(i,j,db);
	    valj+=val;
             ScoresXiXj.put(j,i, val);
         cout<<endl<<j+1<<" "<<i+1<<" a:"<<val<<" i2:   "<<v2<<" i1: "<<v1;
           g.delete_edge(i,j);

            g.put_edge(j,i,-1);
            bTemp.initialize(g,db);
            val = bTemp.MDLScore2(db, j);
            ScoresXiXj.put(i,j, val);
	 //   cout<<endl<<i+1<<" "<<j+1<<" "<<val;

            g.delete_edge(i,j);
        } cout<<endl<<j+1<<" : "<<valj<<" ";
    }

    return ScoresXiXj;

}

 matrx<float> SeconOrderStatistic3( query_database & db )
{
    int i,j, n=db.getN();

    matrx<float> ScoresXiXj(n,n);
    float val;

    ClassBN bTemp(n);
    graph g(n);

    for(j=0;j<n;j++)
    {
        for(i=j+1;i<n;i++)
        {

            g.put_edge(j,i,1);
            bTemp.initialize(g,db);
            float val1 = bTemp.MDLScore(db, i);
             ScoresXiXj.put(j,i, val);

            g.delete_edge(i,j);
            bTemp.initialize(g,db);
            val = bTemp.MDLScore(db, i);
	  //  cout<<"   nullo: "<<val;



            g.put_edge(j,i,-1);
            bTemp.initialize(g,db);
            float val2 = bTemp.MDLScore(db, j);
            ScoresXiXj.put(i,j, val);



            g.delete_edge(i,j);
	    bTemp.initialize(g,db);
            val = bTemp.MDLScore(db, false);
	    //cout<<" nullo: "<<val;

	    if (val1 < val)
	    {
	      //set_output((ofstream *) &cout, 5, 10);
              cout<<endl<<" padre: "<<j+1<<" figlio: "<<i+1<<" v1: "<<val1<<" v2: "<<val2;
	     // set_output((ofstream *) &cout, 5, 10);
	   // cout<<endl<<i+1<<" "<<j+1<<" "<<val2;

	    } else cout<<endl<<"no";

        }
    }
    exit(0);
    return ScoresXiXj;

}


 /*
matrx<float> SeconOrderStatistic2( query_database & db )
{
    int i,j, n=db.getN(), stat_num, num =0;

    matrx<float> ScoresXiXj(n,n);
    float val, tmp;

    ClassBN bTemp(n);
    graph g(n);

    for(j=0;j<n;j++)
    {
        for(i=j+1;i<n;i++)
        {

            g.put_edge(j,i,1);
            bTemp.initialize(g,db);
             val = bTemp.MDLScore3(db, i);
            ScoresXiXj.put(j,i, val);
	     // ************* Si aggiunge la parte relativa al p-value *********
	     // si calcola il numero di stati
	     stat_num = (db.getSNi(j) - 1) * (db.getSNi(i) - 1);
	     tmp  = chisquarecdistribution(stat_num, val);
	     ScoresXiXj.put(j,i, tmp);
	    if (tmp <= 0.005)
	       cout<<endl<<++num<<": "<<j+1<<" "<<i+1<<" ter: "<<tmp<<" v:"<<val;
		// cout<<endl<<j+1<<" -- "<<i+1<<";";
           g.delete_edge(i,j);

            g.put_edge(j,i,-1);
            bTemp.initialize(g,db);
            val = bTemp.MDLScore3(db, j);
	    ScoresXiXj.put(i,j, val);

	    tmp  = chisquarecdistribution(stat_num, val);
	    ScoresXiXj.put(i,j, tmp);
	 //   cout<<endl<<i+1<<" "<<j+1<<" "<<val;

            g.delete_edge(i,j);
        }
    }

    return ScoresXiXj;

}
*/




vectr<float> FirstOrderStatistic( query_database & db )
{
    int i,j, n=db.getN();

    vectr<float> ScoresXi(n);
    float val;

    ClassBN bTemp(n);
    graph g(n);

    for(j=0;j<n;j++) {
       bTemp.initialize(g,db);
       val = bTemp.MDLScore(db,j);
       ScoresXi.put(j, val);
    }

    return ScoresXi;

}


   /*
  ----------------- Procedura swap_nodes ----------------------------------
  *** Scritta il: 24/07/03
  Inverte, nella multilista, i nodi passati come parametro.
  *** Ultima modifica:
  */
  void swap_nodes(List<class Main_node> &multi, int node1, int node2)
  {
    register List<class Main_node>::iterator node_iter, tmp_node_iter;
    register List<class Link>::iterator link_iter;
    int i, tmp_val;

    if (node1 == node2)
      return;

    if (node2 > node1) {
      if (node2 >= multi.size()) {
        cout<<endl<<"ATTENZIONE!: ERRORE IN Multi_individual::swap_nodes"<<endl
	    <<flush;
	return;
      }
    }else {  cout<<endl<<"ATTENZIONE!: ERRORE 2 IN Multi_individual::swap_nodes"<<endl
                 <<flush;
	      return;
       }


    // Si scambiano gli archi dei nodi che precedono il primo nodo da scambiare.
    for (i=0, node_iter= multi.begin(); node_iter != multi.end() && i < node1;
         ++i, ++node_iter)
       node_iter->swap_arcs(node1 - i - 1, node2 - i -1);

       //cout<<endl<<"node_iter->val: "<<node_iter->val;

    // Adesso si effettuano gli scambi tra gli elementi del primo nodo da
    for (link_iter  = node_iter->sub.begin(), i=0, tmp_node_iter = node_iter;
         i < node2 - node1 - 1; ++i, ++link_iter)
       {
         tmp_node_iter++;
         tmp_val = tmp_node_iter->set_arc_value(node2 - node1 - 2 - i, link_iter->val);
         link_iter->val = tmp_val;
       }

    // Salto quello che collega node1 a node2.
    ++link_iter;

   // Si incrementa il puntatore per puntare a node2.
   tmp_node_iter++;


    for (i=0;  link_iter != node_iter->sub.end(); ++i, ++link_iter) {
         tmp_val = tmp_node_iter->set_arc_value(i, link_iter->val);
	 // cout<<endl<<"val: "<<tmp_node_iter->val;
         link_iter->val = tmp_val;
    }
    //cout<<endl<<"n1: "<<node_iter->val+1<<" n2: "<<tmp_node_iter->val+1;
    // Adesso si scambiano le label dei nodi.
    tmp_val = node_iter->val;
    node_iter->val = tmp_node_iter->val;
    tmp_node_iter->val = tmp_val;


    return;
  }

  /*
  ----------------- Procedura move_node ----------------------------
  *** Scritta il: 24/07/03
  E' la procedura costruttrice della classe. Genera una multilista vuota
  *** Ultima modifica:
  */
  void move_node(List<class Main_node> &multi, int node, int shift)
  {

     int i, v;

     if (shift > 0)
       v = 1;
     else v = -1;

     if ((node + shift < 0) || (node + shift >= multi.size())) {
       cout<<endl<<"ATTENZIONE: ERRORE in move_node! "<<flush;
       cout<<endl<<"node:"<<node<<" s:"<<shift;
       cout<<endl<<"**";

       return;
     }
     //cout<<endl<<"node:"<<node<<" s:"<<shift;
     for (i=0; i < v*shift; ++i)
        if (v>0)
          swap_nodes(multi, node+ v*i, node + v*(i+1));
	else  {
	  swap_nodes(multi, node + v*(i+1), node+ v*i);
	  return;
	}




     return;
  }

 void find_max(matrx<float> *sm, int &r, int &c)
 {
   int  i, j, n;


   n = sm->get_row();

   if (n != sm->get_column()) {
     cout<<endl<<"ATTENZIONE!: ERRORE in find_max"<<endl<<flush;
     return;
   }

   r= c = 0;

   for (i=0; i < n; ++i)
      for (j=0; j < n; ++j)
        if (sm->get(i,j) > sm->get(r,c)) {
	  r = i;
	  c = j;
	}
   sm->put(r,c,-1.0);
 }


vectr<int> build_DT_ord(graph *g, matrx<float> *m)
  {
    int i, arcs, n, j;
    vectr<int> *vec;
    //vect
    arcs = 0;
    n = g->n_nodes();
    vec = new vectr<int>(n);


       while (arcs < n - 1)  {
         find_max(m, i,j);
         g->put_edge(i,j, 1);
         g->topologic_sort();
         if (g->get_control()) {
           arcs++;
	 //  cout<<endl<<i<<"->"<<j<<";"<<flush;
	 }
         else g->delete_edge (i, j);

       }

       for (i=0; i < n; ++i)
          vec->put(i, g->ancestral_ordering(i));


     vec->printvector();
     //exit(0);

     return *vec;

 }
int find_max(matrx<float> *sm, bool *mst, bool *out, int N_nodes, int &mst_index)
 {
   int  i, j, max_i, max_j;
   float max_val = -1.0;


   for (i=0; i < N_nodes; ++i)
      for (j=0; j < N_nodes; ++j)

         if (mst[i] && out[j]) {
	  // cout<<endl<<"i: "<<i<<" j: "<<j<<" max:"<<max_val;
	   if (sm->get(i,j) > max_val) {
	     max_i = i;
	     max_j = j;
	     max_val = sm->get(i,j);

	   } else if (sm->get(i,j) == max_val)
	            if (flip (0.5)) {
		      max_i = i;
	              max_j = j;
		    } }

   mst_index = max_i;
   //cout<<endl<<"max:"<<sm->get(max_i, max_j);
   return max_j;


 }
int find_first(matrx<float> *sm, int N_nodes)
 {
   int  i, j, max_i, max_j;
   float max_val = -1.0;


   for (i=0; i < N_nodes; ++i)
      for (j=0; j < N_nodes; ++j)
	  // cout<<endl<<"i: "<<i<<" j: "<<j<<" max:"<<max_val;
	   if (sm->get(i,j) > max_val) {
	     max_i = i;
	     max_j = j;
	     max_val = sm->get(i,j);

	   } else if (sm->get(i,j) == max_val)
	            if (flip (0.5)) {
		      max_i = i;
	              max_j = j;
		    }

   if (flip(0.5))
     return max_i;
   else return max_j;


 }
/* ATTENZIONE! z � la variabile condizionale   */

  float G_counter(int x, int y, int z, int sx, int sy, int sz, query_database &db)
  {

    int i, N_samples, xyz_counter, xz_counter, yz_counter, z_counter;
    float Pxyz, Pxz, Pyz, Pz;

    xyz_counter = xz_counter = yz_counter = z_counter = 0;//ALE 1;

    N_samples = db.getNS();


    for (i=0; i < N_samples; ++i)
       if (db.getDij(z,i) == sz) {
         ++z_counter;

         if (db.getDij(x,i) == sx)
           ++xz_counter;

         if (db.getDij(y,i) == sy) {
           ++yz_counter;

         if (db.getDij(x,i) == sx)
           ++xyz_counter;

         }
       }

       Pxyz = (float) xyz_counter/ N_samples;
       Pxz  = (float) xz_counter/ N_samples;
       Pyz  = (float) yz_counter/ N_samples;
       Pz   = (float) z_counter/ N_samples;

	   if((Pyz==0)||(Pxz==0)||(Pz==0))
	     return 0;
	   else return Pxyz *log((Pxyz*Pz)/(Pyz*Pxz));
  }

  float G_squared(int x, int y, int z, query_database &db)
  {
     int i, j, k, nx, ny, nz;

     float G_sum = 0.0;

     nx = db.getSNi(x);
     ny = db.getSNi(y);
     nz = db.getSNi(z);


     for(i=1; i <= nx; ++i)
        for(j=1; j <= ny; ++j)
	   for(k=1; k <= nz; ++k)
	      G_sum = G_counter(x, y, z, i, j, k, db);


    //return G_sum;
     double fd = (nx-1)*(ny-1)*nz;
     double G_value= 2 * db.getN()*(double) G_sum;

/*  if (G_value > 0.0)
    if (chisquarecdistribution(fd, G_value)< 0.98)te
   cout<<endl<<" G:"<<G_value<<" fd: "<<fd<<" x:"<<x+1<<" y:"<<y+1<<" z:"<<z+1<<" chi:"<<chisquarecdistribution(fd, G_value);       */
   if (G_value > 0.0) {//set_output((ofstream *)&cout, 10, 10);
       cout<<z+1<<":"<<chisquarecdistribution(fd, G_value)<<";";
       return chisquarecdistribution(fd, G_value);
   }
  else return 0.0;


  }

  float G_test(int x, int y, query_database &db)
  {
     float tmp, maxG = -2.0;
     int i;


     for (i=0; i < db.getN(); ++i)
        if ((i != x) && (i != y)) {
	  tmp = G_squared(x, y, i, db);
	  if (tmp > maxG)
	    maxG = tmp;
	}

     return maxG;

  }


float M_counter(int x, int y, int sx, int sy, query_database &db)
  {

    int i, N_samples, xy_counter, x_counter, y_counter;
    float Pxy, Px, Py;

    xy_counter = x_counter = y_counter = 0;

    N_samples = db.getNS();


    for (i=0; i < N_samples; ++i) {
       if (db.getDij(x,i) == sx)
         ++x_counter;

       if (db.getDij(y,i) == sy) {
         ++y_counter;

         if (db.getDij(x,i) == sx)
           ++xy_counter;
       }

    }

      /* if (x_counter == 0)
         ++x_counter;
       if (y_counter == 0)
         ++y_counter;

       if(xy_counter == 0)
         ++xy_counter;
       */

       Pxy = (float) xy_counter/ N_samples;
       Px  = (float) x_counter/ N_samples;
       Py  = (float) y_counter/ N_samples;
		float r;
       if((Px==0)||(Py==0) || (Pxy == 0)) // PROVA
		   return 0;
	   else
           r =  Pxy *log(Pxy/(Py*Px)); /**/

      /*float d = Pxy - Px*Py;
	  r = (d*d)/(Px*Py);*/

      return r; 

  }

   float Mutual(int x, int y, query_database &db)
  {
     int i, j, k, n, nx, ny;

     float M_sum = 0.0;


    // cout<<endl<<"INI, x: "<<x<<" y: "<<y<<flush;
     nx = db.getSNi(x);
     ny = db.getSNi(y);
    //cout<<endl<<"FIN"<<flush;

     for(i=1; i <= nx; ++i)
        for(j=1; j <=  ny; ++j)
	   M_sum += M_counter(x, y, i, j, db);


	// return  M_sum; // PROVA



     double fd = (nx-1)*(ny-1);
     double M_value= (double) M_sum* db.getN();

	 //return M_value;

	 if (M_value > 0.0)
       return chisquaredistribution(fd, M_value);
     else {
     cout<<"ECCO!";
     return 0.0;

     }



  }

  void ini_min_scores(int n)
  {
    int i, j;

   min_scores = new min_score[n];

    for (i=0; i < n; ++i) {
       min_scores[i].score = 10000000;
       min_scores[i].pars = new bool[n];
       for(j=0; j < n; ++j)
          min_scores[i].pars[j]= false;
    }


  }

  void set_min_score(int node, float val, vectr<int> pars)
  {
     int i, p;

     /* Controllo se sono uguali.
     if (val == min_scores[node].score)
       if (flip(0.5))
         return;
     */
     min_scores[node].score = val;

     for( i=0; i < pars.get_lenght(); ++i) {
        p =  pars.get(i);
        min_scores[node].pars[p] = true;
     }

     return;
  }

  float give_min_score(int node)
  {
    return min_scores[node].score;
  }

  bool is_father(int node, int f)
  {
    return min_scores[node].pars[f];
  }

  void comp_mutual_values (mutual_values m, int N_nodes) 
  {
    matrx<float> *mutualMat = new matrx<float>(N_nodes, N_nodes);
    *mutualMat = G_statistics(*db);
	  //mutualMat->printmatrix();
 
    // Calcolo della media, del minimo e del massimo degli score,
    int i, j, num=0;
    float sum, s;

    sum = 0.0;
    m.min = m.max = mutualMat->get(0,1);

		for (i=0; i < N_nodes; ++i)
       for (j=i+1; j < N_nodes; ++j)  {
	        sum += mutualMat->get(i,j);
	        ++num;
	        // Calcolo di max e min.
	        s = mutualMat->get(i,j);
	        if (s > m.max)
	          m.max = s;
	        if (s < m.min)
	          m.min = s;
	     }

    m.avg = sum / num;

    sum = 0.0;
    // Calcolo della dev std
    for (i=0; i < N_nodes; ++i)
       for (j=i+1; j < N_nodes; ++j)
          sum += pow(mutualMat->get(i,j) - m.avg, 2); 
 
    m.dev = sum / num;  
    
    return;
	}
